From c4aae784ee3c5befd5ab76b3c947e8096c1ae59e Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 10 Jan 2018 20:53:58 +0100 Subject: [PATCH 01/25] Improve tooltip text quality --- resources/qml/PrinterOutput/ExtruderBox.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index a7141262a9..4e15ba75c5 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -52,7 +52,7 @@ Item { base.showTooltip( base, - {x: 0, y: extruderTargetTemperature.mapToItem(base, 0, -parent.height / 4).y}, + {x: 0, y: extruderTargetTemperature.mapToItem(base, 0, Math.floor(-parent.height / 4)).y}, catalog.i18nc("@tooltip", "The target temperature of the hotend. The hotend will heat up or cool down towards this temperature. If this is 0, the hotend heating is turned off.") ); } @@ -85,7 +85,7 @@ Item { base.showTooltip( base, - {x: 0, y: parent.mapToItem(base, 0, -parent.height / 4).y}, + {x: 0, y: parent.mapToItem(base, 0, Math.floor(-parent.height / 4)).y}, catalog.i18nc("@tooltip", "The current temperature of this extruder.") ); } From fb9d841c90e4b0d685bcba570da1d0b2495a77ce Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 10 Jan 2018 21:41:59 +0100 Subject: [PATCH 02/25] Add per-extruder preheat controls These are lifted from the bed preheat controls and are not functional at the moment --- cura/PrinterOutput/PrinterOutputController.py | 1 + cura/PrinterOutput/PrinterOutputModel.py | 7 + .../ClusterUM3PrinterOutputController.py | 1 + resources/qml/PrinterOutput/ExtruderBox.qml | 258 +++++++++++++++++- 4 files changed, 264 insertions(+), 3 deletions(-) diff --git a/cura/PrinterOutput/PrinterOutputController.py b/cura/PrinterOutput/PrinterOutputController.py index 86ca10e2d3..6bfe562f1a 100644 --- a/cura/PrinterOutput/PrinterOutputController.py +++ b/cura/PrinterOutput/PrinterOutputController.py @@ -15,6 +15,7 @@ class PrinterOutputController: self.can_pause = True self.can_abort = True self.can_pre_heat_bed = True + self.can_pre_heat_extruders = True self.can_control_manually = True self._output_device = output_device diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 8234989519..cbed44fa65 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -218,6 +218,13 @@ class PrinterOutputModel(QObject): return self._controller.can_pre_heat_bed return False + # Does the printer support pre-heating the bed at all + @pyqtProperty(bool, constant=True) + def canPreHeatExtruders(self): + if self._controller: + return self._controller.can_pre_heat_extruders + return False + # Does the printer support pause at all @pyqtProperty(bool, constant=True) def canPause(self): diff --git a/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py b/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py index 4615cd62dc..8909a15d2c 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py @@ -13,6 +13,7 @@ class ClusterUM3PrinterOutputController(PrinterOutputController): def __init__(self, output_device): super().__init__(output_device) self.can_pre_heat_bed = False + self.can_pre_heat_extruders = False self.can_control_manually = False def setJobState(self, job: "PrintJobOutputModel", state: str): diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index 4e15ba75c5..609bd65c1d 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -39,7 +39,7 @@ Item color: UM.Theme.getColor("text_inactive") anchors.right: parent.right anchors.rightMargin: UM.Theme.getSize("default_margin").width - anchors.bottom: extruderTemperature.bottom + anchors.bottom: extruderCurrentTemperature.bottom MouseArea //For tooltip. { @@ -65,7 +65,7 @@ Item } Label //Temperature indication. { - id: extruderTemperature + id: extruderCurrentTemperature text: Math.round(extruderModel.hotendTemperature) + "°C" //text: (connectedPrinter != null && connectedPrinter.hotendIds[index] != null && connectedPrinter.hotendTemperatures[index] != null) ? Math.round(connectedPrinter.hotendTemperatures[index]) + "°C" : "" color: UM.Theme.getColor("text") @@ -76,7 +76,7 @@ Item MouseArea //For tooltip. { - id: extruderTemperatureTooltipArea + id: extruderCurrentTemperatureTooltipArea hoverEnabled: true anchors.fill: parent onHoveredChanged: @@ -97,6 +97,258 @@ Item } } + Rectangle //Input field for pre-heat temperature. + { + id: preheatTemperatureControl + color: !enabled ? UM.Theme.getColor("setting_control_disabled") : showError ? UM.Theme.getColor("setting_validation_error_background") : UM.Theme.getColor("setting_validation_ok") + property var showError: + { + if(extruderTemperature.properties.maximum_value != "None" && extruderTemperature.properties.maximum_value < Math.floor(preheatTemperatureInput.text)) + { + return true; + } else + { + return false; + } + } + enabled: + { + if (extruderModel == null) + { + return false; //Can't preheat if not connected. + } + if (!connectedPrinter.acceptsCommands) + { + return false; //Not allowed to do anything. + } + if (connectedPrinter.jobState == "printing" || connectedPrinter.jobState == "pre_print" || connectedPrinter.jobState == "resuming" || connectedPrinter.jobState == "pausing" || connectedPrinter.jobState == "paused" || connectedPrinter.jobState == "error" || connectedPrinter.jobState == "offline") + { + return false; //Printer is in a state where it can't react to pre-heating. + } + return true; + } + border.width: UM.Theme.getSize("default_lining").width + border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : preheatTemperatureInputMouseArea.containsMouse ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border") + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.bottom: parent.bottom + anchors.bottomMargin: UM.Theme.getSize("default_margin").height + width: Math.floor(UM.Theme.getSize("setting_control").width * 0.75) + height: UM.Theme.getSize("setting_control").height + visible: extruderModel != null ? extruderModel.canPreHeatExtruders: true + Rectangle //Highlight of input field. + { + anchors.fill: parent + anchors.margins: UM.Theme.getSize("default_lining").width + color: UM.Theme.getColor("setting_control_highlight") + opacity: preheatTemperatureControl.hovered ? 1.0 : 0 + } + MouseArea //Change cursor on hovering. + { + id: preheatTemperatureInputMouseArea + hoverEnabled: true + anchors.fill: parent + cursorShape: Qt.IBeamCursor + + onHoveredChanged: + { + if (containsMouse) + { + base.showTooltip( + base, + {x: 0, y: preheatTemperatureInputMouseArea.mapToItem(base, 0, 0).y}, + catalog.i18nc("@tooltip of temperature input", "The temperature to pre-heat the extruder to.") + ); + } + else + { + base.hideTooltip(); + } + } + } + TextInput + { + id: preheatTemperatureInput + font: UM.Theme.getFont("default") + color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text") + selectByMouse: true + maximumLength: 5 + enabled: parent.enabled + validator: RegExpValidator { regExp: /^-?[0-9]{0,9}[.,]?[0-9]{0,10}$/ } //Floating point regex. + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("setting_unit_margin").width + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + renderType: Text.NativeRendering + + Component.onCompleted: + { + if (!extruderTemperature.properties.value) + { + text = ""; + } + else + { + text = extruderTemperature.properties.value; + } + } + } + } + + Button //The pre-heat button. + { + id: preheatButton + height: UM.Theme.getSize("setting_control").height + visible: extruderModel != null ? extruderModel.canPreHeatExtruders: true + enabled: + { + if (!preheatTemperatureControl.enabled) + { + return false; //Not connected, not authenticated or printer is busy. + } + if (extruderModel.isPreheating) + { + return true; + } + if (extruderTemperature.properties.minimum_value != "None" && Math.floor(preheatTemperatureInput.text) < Math.floor(extruderTemperature.properties.minimum_value)) + { + return false; //Target temperature too low. + } + if (extruderTemperature.properties.maximum_value != "None" && Math.floor(preheatTemperatureInput.text) > Math.floor(extruderTemperature.properties.maximum_value)) + { + return false; //Target temperature too high. + } + if (Math.floor(preheatTemperatureInput.text) == 0) + { + return false; //Setting the temperature to 0 is not allowed (since that cancels the pre-heating). + } + return true; //Preconditions are met. + } + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: UM.Theme.getSize("default_margin").width + style: ButtonStyle { + background: Rectangle + { + border.width: UM.Theme.getSize("default_lining").width + implicitWidth: actualLabel.contentWidth + (UM.Theme.getSize("default_margin").width * 2) + 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 + } + } + + Label + { + id: actualLabel + anchors.centerIn: parent + 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: + { + if(extruderModel == null) + { + return "" + } + if(extruderModel.isPreheating ) + { + return catalog.i18nc("@button Cancel pre-heating", "Cancel") + } else + { + return catalog.i18nc("@button", "Pre-heat") + } + } + } + } + } + + onClicked: + { + if (!extruderModel.isPreheating) + { + extruderModel.preheatExtruder(preheatTemperatureInput.text, 900); + } + else + { + extruderModel.cancelPreheatExtruder(); + } + } + + onHoveredChanged: + { + if (hovered) + { + base.showTooltip( + base, + {x: 0, y: preheatButton.mapToItem(base, 0, 0).y}, + catalog.i18nc("@tooltip of pre-heat", "Heat the extruder in advance before printing. You can continue adjusting your print while it is heating, and you won't have to wait for the extruder to heat up when you're ready to print.") + ); + } + else + { + base.hideTooltip(); + } + } + } + Rectangle //Material colour indication. { id: materialColor From 52412cb1cdf328acd8c9e14c150063df5c98060b Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 10 Jan 2018 21:59:17 +0100 Subject: [PATCH 03/25] Remove commented-out code --- resources/qml/PrinterOutput/ExtruderBox.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index 609bd65c1d..80f2b94f6c 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -34,7 +34,6 @@ Item { id: extruderTargetTemperature text: Math.round(extruderModel.targetHotendTemperature) + "°C" - //text: (connectedPrinter != null && connectedPrinter.hotendIds[index] != null && connectedPrinter.targetHotendTemperatures[index] != null) ? Math.round(connectedPrinter.targetHotendTemperatures[index]) + "°C" : "" font: UM.Theme.getFont("small") color: UM.Theme.getColor("text_inactive") anchors.right: parent.right @@ -67,7 +66,6 @@ Item { id: extruderCurrentTemperature text: Math.round(extruderModel.hotendTemperature) + "°C" - //text: (connectedPrinter != null && connectedPrinter.hotendIds[index] != null && connectedPrinter.hotendTemperatures[index] != null) ? Math.round(connectedPrinter.hotendTemperatures[index]) + "°C" : "" color: UM.Theme.getColor("text") font: UM.Theme.getFont("large") anchors.right: extruderTargetTemperature.left From d3f94a1137cea7352bdb2ec3ef60b09a7ff80f2f Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 10 Jan 2018 22:36:52 +0100 Subject: [PATCH 04/25] Get preheat temperatures from the proper stacks --- resources/qml/PrinterOutput/ExtruderBox.qml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index 80f2b94f6c..f1d4a61604 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -15,6 +15,18 @@ Item //width: index == machineExtruderCount.properties.value - 1 && index % 2 == 0 ? extrudersGrid.width : Math.floor(extrudersGrid.width / 2 - UM.Theme.getSize("sidebar_lining_thin").width / 2) implicitWidth: parent.width implicitHeight: UM.Theme.getSize("sidebar_extruder_box").height + + UM.SettingPropertyProvider + { + id: extruderTemperature + containerStackId: Cura.ExtruderManager.extruderIds[position] + key: "material_print_temperature" + watchedProperties: ["value", "minimum_value", "maximum_value", "resolve"] + storeIndex: 0 + + property var resolve: Cura.MachineManager.activeStackId != Cura.MachineManager.activeMachineId ? properties.resolve : "None" + } + Rectangle { id: background From 70cd6aad534ac43d6def756ee250dc60086de13f Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 11 Jan 2018 15:17:30 +0100 Subject: [PATCH 05/25] Remove commented-out code --- resources/qml/PrinterOutput/ExtruderBox.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index f1d4a61604..171fbf2013 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -12,7 +12,6 @@ Item property alias color: background.color property var extruderModel property var position: index - //width: index == machineExtruderCount.properties.value - 1 && index % 2 == 0 ? extrudersGrid.width : Math.floor(extrudersGrid.width / 2 - UM.Theme.getSize("sidebar_lining_thin").width / 2) implicitWidth: parent.width implicitHeight: UM.Theme.getSize("sidebar_extruder_box").height From bc5b5ac283765078b25c157e6ec64738169afdf9 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 11 Jan 2018 15:27:38 +0100 Subject: [PATCH 06/25] Implement preheating hotends for USB printing --- cura/PrinterOutput/ExtruderOuputModel.py | 33 ++++++++++++- cura/PrinterOutput/PrinterOutputController.py | 2 +- cura/PrinterOutput/PrinterOutputModel.py | 6 +-- .../ClusterUM3PrinterOutputController.py | 2 +- .../USBPrinting/USBPrinterOutputController.py | 49 +++++++++++++++++-- resources/qml/PrinterOutput/ExtruderBox.qml | 14 +++--- 6 files changed, 89 insertions(+), 17 deletions(-) diff --git a/cura/PrinterOutput/ExtruderOuputModel.py b/cura/PrinterOutput/ExtruderOuputModel.py index b0be6cbbe4..befde28f99 100644 --- a/cura/PrinterOutput/ExtruderOuputModel.py +++ b/cura/PrinterOutput/ExtruderOuputModel.py @@ -17,14 +17,23 @@ class ExtruderOutputModel(QObject): targetHotendTemperatureChanged = pyqtSignal() hotendTemperatureChanged = pyqtSignal() activeMaterialChanged = pyqtSignal() + isPreheatingChanged = pyqtSignal() - def __init__(self, printer: "PrinterOutputModel", parent=None): + def __init__(self, printer: "PrinterOutputModel", position: int, parent=None): super().__init__(parent) self._printer = printer + self._position = position self._target_hotend_temperature = 0 self._hotend_temperature = 0 self._hotend_id = "" self._active_material = None # type: Optional[MaterialOutputModel] + self._is_preheating = False + + def getPrinter(self): + return self._printer + + def getPosition(self): + return self._position @pyqtProperty(QObject, notify = activeMaterialChanged) def activeMaterial(self) -> "MaterialOutputModel": @@ -68,3 +77,25 @@ class ExtruderOutputModel(QObject): if self._hotend_id != id: self._hotend_id = id self.hotendIDChanged.emit() + + def updateIsPreheating(self, pre_heating): + if self._is_preheating != pre_heating: + self._is_preheating = pre_heating + self.isPreheatingChanged.emit() + + @pyqtProperty(bool, notify=isPreheatingChanged) + def isPreheating(self): + return self._is_preheating + + ## Pre-heats the extruder before printer. + # + # \param temperature The temperature to heat the extruder to, in degrees + # Celsius. + # \param duration How long the bed should stay warm, in seconds. + @pyqtSlot(float, float) + def preheatHotend(self, temperature, duration): + self._printer._controller.preheatHotend(self, temperature, duration) + + @pyqtSlot() + def cancelPreheatHotend(self): + self._printer._controller.cancelPreheatHotend(self) \ No newline at end of file diff --git a/cura/PrinterOutput/PrinterOutputController.py b/cura/PrinterOutput/PrinterOutputController.py index 6bfe562f1a..512ac4aa02 100644 --- a/cura/PrinterOutput/PrinterOutputController.py +++ b/cura/PrinterOutput/PrinterOutputController.py @@ -15,7 +15,7 @@ class PrinterOutputController: self.can_pause = True self.can_abort = True self.can_pre_heat_bed = True - self.can_pre_heat_extruders = True + self.can_pre_heat_hotends = True self.can_control_manually = True self._output_device = output_device diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index cbed44fa65..f510829101 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -32,7 +32,7 @@ class PrinterOutputModel(QObject): self._name = "" self._key = "" # Unique identifier self._controller = output_controller - self._extruders = [ExtruderOutputModel(printer=self) for i in range(number_of_extruders)] + self._extruders = [ExtruderOutputModel(printer=self, position=i) for i in range(number_of_extruders)] self._head_position = Vector(0, 0, 0) self._active_print_job = None # type: Optional[PrintJobOutputModel] self._firmware_version = firmware_version @@ -220,9 +220,9 @@ class PrinterOutputModel(QObject): # Does the printer support pre-heating the bed at all @pyqtProperty(bool, constant=True) - def canPreHeatExtruders(self): + def canPreHeatHotends(self): if self._controller: - return self._controller.can_pre_heat_extruders + return self._controller.can_pre_heat_hotends return False # Does the printer support pause at all diff --git a/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py b/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py index 8909a15d2c..076c4584af 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py @@ -13,7 +13,7 @@ class ClusterUM3PrinterOutputController(PrinterOutputController): def __init__(self, output_device): super().__init__(output_device) self.can_pre_heat_bed = False - self.can_pre_heat_extruders = False + self.can_pre_heat_hotends = False self.can_control_manually = False def setJobState(self, job: "PrintJobOutputModel", state: str): diff --git a/plugins/USBPrinting/USBPrinterOutputController.py b/plugins/USBPrinting/USBPrinterOutputController.py index ba45e7b0ca..5640db4a63 100644 --- a/plugins/USBPrinting/USBPrinterOutputController.py +++ b/plugins/USBPrinting/USBPrinterOutputController.py @@ -19,6 +19,11 @@ class USBPrinterOuptutController(PrinterOutputController): self._preheat_bed_timer.timeout.connect(self._onPreheatBedTimerFinished) self._preheat_printer = None + self._preheat_extruders_timer = QTimer() + self._preheat_extruders_timer.setSingleShot(True) + self._preheat_extruders_timer.timeout.connect(self._onPreheatHotendsTimerFinished) + self._preheat_extruders = set() + def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed): self._output_device.sendCommand("G91") self._output_device.sendCommand("G0 X%s Y%s Z%s F%s" % (x, y, z, speed)) @@ -42,6 +47,9 @@ class USBPrinterOuptutController(PrinterOutputController): self._output_device.cancelPrint() pass + def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int): + self._output_device.sendCommand("M140 S%s" % temperature) + def preheatBed(self, printer: "PrinterOutputModel", temperature, duration): try: temperature = round(temperature) # The API doesn't allow floating point. @@ -60,9 +68,42 @@ class USBPrinterOuptutController(PrinterOutputController): self._preheat_bed_timer.stop() printer.updateIsPreheating(False) - def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int): - self._output_device.sendCommand("M140 S%s" % temperature) - def _onPreheatBedTimerFinished(self): self.setTargetBedTemperature(self._preheat_printer, 0) - self._preheat_printer.updateIsPreheating(False) \ No newline at end of file + self._preheat_printer.updateIsPreheating(False) + + def setTargetHotendTemperature(self, printer: "PrinterOutputModel", position: int, temperature: int): + self._output_device.sendCommand("M104 S%s T%s" % (temperature, position)) + + def _onPreheatHotendsTimerFinished(self): + for extruder in self._preheat_extruders: + self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), 0) + self._preheat_extruders = set() + self._preheat_printer.updateIsPreheating(False) + + def cancelPreheatHotend(self, extruder: "ExtruderOutputModel"): + self.preheatHotend(extruder, temperature=0, duration=0) + self._preheat_extruders_timer.stop() + try: + self._preheat_extruders.remove(extruder) + except KeyError: + pass + extruder.updateIsPreheating(False) + + def preheatHotend(self, extruder: "ExtruderOutputModel", temperature, duration): + position = extruder.getPosition() + number_of_extruders = len(extruder.getPrinter().extruders) + if position >= number_of_extruders: + return # Got invalid extruder nr, can't pre-heat. + + try: + temperature = round(temperature) # The API doesn't allow floating point. + duration = round(duration) + except ValueError: + return # Got invalid values, can't pre-heat. + + self.setTargetHotendTemperature(extruder.getPrinter(), position, temperature=temperature) + self._preheat_extruders_timer.setInterval(duration * 1000) + self._preheat_extruders_timer.start() + self._preheat_extruders.add(extruder) + extruder.updateIsPreheating(True) \ No newline at end of file diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index 171fbf2013..dee9377425 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -95,7 +95,7 @@ Item base.showTooltip( base, {x: 0, y: parent.mapToItem(base, 0, Math.floor(-parent.height / 4)).y}, - catalog.i18nc("@tooltip", "The current temperature of this extruder.") + catalog.i18nc("@tooltip", "The current temperature of this hotend.") ); } else @@ -144,7 +144,7 @@ Item anchors.bottomMargin: UM.Theme.getSize("default_margin").height width: Math.floor(UM.Theme.getSize("setting_control").width * 0.75) height: UM.Theme.getSize("setting_control").height - visible: extruderModel != null ? extruderModel.canPreHeatExtruders: true + visible: extruderModel != null ? extruderModel.canPreHeatHotends: true Rectangle //Highlight of input field. { anchors.fill: parent @@ -166,7 +166,7 @@ Item base.showTooltip( base, {x: 0, y: preheatTemperatureInputMouseArea.mapToItem(base, 0, 0).y}, - catalog.i18nc("@tooltip of temperature input", "The temperature to pre-heat the extruder to.") + catalog.i18nc("@tooltip of temperature input", "The temperature to pre-heat the hotend to.") ); } else @@ -208,7 +208,7 @@ Item { id: preheatButton height: UM.Theme.getSize("setting_control").height - visible: extruderModel != null ? extruderModel.canPreHeatExtruders: true + visible: extruderModel != null ? extruderModel.canPreHeatHotends: true enabled: { if (!preheatTemperatureControl.enabled) @@ -333,11 +333,11 @@ Item { if (!extruderModel.isPreheating) { - extruderModel.preheatExtruder(preheatTemperatureInput.text, 900); + extruderModel.preheatHotend(preheatTemperatureInput.text, 900); } else { - extruderModel.cancelPreheatExtruder(); + extruderModel.cancelPreheatHotend(); } } @@ -348,7 +348,7 @@ Item base.showTooltip( base, {x: 0, y: preheatButton.mapToItem(base, 0, 0).y}, - catalog.i18nc("@tooltip of pre-heat", "Heat the extruder in advance before printing. You can continue adjusting your print while it is heating, and you won't have to wait for the extruder to heat up when you're ready to print.") + catalog.i18nc("@tooltip of pre-heat", "Heat the hotend in advance before printing. You can continue adjusting your print while it is heating, and you won't have to wait for the hotend to heat up when you're ready to print.") ); } else From 7994c95bbe4cf9f6928b3e4baf811e3705eb63cf Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 17 Jan 2018 18:03:01 +0100 Subject: [PATCH 07/25] Add unit to preheat temperature boxes --- resources/qml/PrinterOutput/ExtruderBox.qml | 23 +++++++++++++----- resources/qml/PrinterOutput/HeatedBedBox.qml | 25 ++++++++++++++------ resources/themes/cura-light/theme.json | 2 ++ 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index dee9377425..4aacef1a94 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -138,13 +138,13 @@ Item } border.width: UM.Theme.getSize("default_lining").width border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : preheatTemperatureInputMouseArea.containsMouse ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border") - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.right: preheatButton.left + anchors.rightMargin: UM.Theme.getSize("default_margin").width anchors.bottom: parent.bottom anchors.bottomMargin: UM.Theme.getSize("default_margin").height - width: Math.floor(UM.Theme.getSize("setting_control").width * 0.75) - height: UM.Theme.getSize("setting_control").height - visible: extruderModel != null ? extruderModel.canPreHeatHotends: true + width: UM.Theme.getSize("monitor_preheat_temperature_control").width + height: UM.Theme.getSize("monitor_preheat_temperature_control").height + visible: extruderModel != null ? extruderModel.canPreHeatHotends && !extruderModel.isPreheating : true Rectangle //Highlight of input field. { anchors.fill: parent @@ -175,6 +175,17 @@ Item } } } + Label + { + id: unit + anchors.right: parent.right + anchors.rightMargin: UM.Theme.getSize("setting_unit_margin").width + anchors.verticalCenter: parent.verticalCenter + + text: "°C"; + color: UM.Theme.getColor("setting_unit") + font: UM.Theme.getFont("default") + } TextInput { id: preheatTemperatureInput @@ -186,7 +197,7 @@ Item validator: RegExpValidator { regExp: /^-?[0-9]{0,9}[.,]?[0-9]{0,10}$/ } //Floating point regex. anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("setting_unit_margin").width - anchors.right: parent.right + anchors.right: unit.left anchors.verticalCenter: parent.verticalCenter renderType: Text.NativeRendering diff --git a/resources/qml/PrinterOutput/HeatedBedBox.qml b/resources/qml/PrinterOutput/HeatedBedBox.qml index bc89da2251..8d1e37b23d 100644 --- a/resources/qml/PrinterOutput/HeatedBedBox.qml +++ b/resources/qml/PrinterOutput/HeatedBedBox.qml @@ -122,13 +122,13 @@ Item } border.width: UM.Theme.getSize("default_lining").width border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : preheatTemperatureInputMouseArea.containsMouse ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border") - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.right: preheatButton.left + anchors.rightMargin: UM.Theme.getSize("default_margin").width anchors.bottom: parent.bottom anchors.bottomMargin: UM.Theme.getSize("default_margin").height - width: UM.Theme.getSize("setting_control").width - height: UM.Theme.getSize("setting_control").height - visible: printerModel != null ? printerModel.canPreHeatBed: true + width: UM.Theme.getSize("monitor_preheat_temperature_control").width + height: UM.Theme.getSize("monitor_preheat_temperature_control").height + visible: printerModel != null ? printerModel.canPreHeatBed && !printerModel.isPreheating : true Rectangle //Highlight of input field. { anchors.fill: parent @@ -159,18 +159,29 @@ Item } } } + Label + { + id: unit + anchors.right: parent.right + anchors.rightMargin: UM.Theme.getSize("setting_unit_margin").width + anchors.verticalCenter: parent.verticalCenter + + text: "°C"; + color: UM.Theme.getColor("setting_unit") + font: UM.Theme.getFont("default") + } TextInput { id: preheatTemperatureInput font: UM.Theme.getFont("default") color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text") selectByMouse: true - maximumLength: 10 + maximumLength: 5 enabled: parent.enabled validator: RegExpValidator { regExp: /^-?[0-9]{0,9}[.,]?[0-9]{0,10}$/ } //Floating point regex. anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("setting_unit_margin").width - anchors.right: parent.right + anchors.right: unit.left anchors.verticalCenter: parent.verticalCenter renderType: Text.NativeRendering diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 51c96a5f82..aebd527749 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -379,6 +379,8 @@ "save_button_save_to_button": [0.3, 2.7], "save_button_specs_icons": [1.4, 1.4], + "monitor_preheat_temperature_control": [4.5, 2.0], + "modal_window_minimum": [60.0, 45], "license_window_minimum": [45, 45], "wizard_progress": [10.0, 0.0], From b68a30662aead1418c931d7c58ec2d2ab24f25f5 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 17 Jan 2018 21:21:13 +0100 Subject: [PATCH 08/25] Add stubs to PrinterOutputController --- cura/PrinterOutput/PrinterOutputController.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cura/PrinterOutput/PrinterOutputController.py b/cura/PrinterOutput/PrinterOutputController.py index 512ac4aa02..6710216a02 100644 --- a/cura/PrinterOutput/PrinterOutputController.py +++ b/cura/PrinterOutput/PrinterOutputController.py @@ -34,6 +34,12 @@ class PrinterOutputController: def preheatBed(self, printer: "PrinterOutputModel", temperature, duration): Logger.log("w", "Preheat bed not implemented in controller") + def cancelPreheatHotend(self, extruder: "ExtruderOutputModel"): + Logger.log("w", "Cancel preheat hotend not implemented in controller") + + def preheatHotend(self, extruder: "ExtruderOutputModel", temperature, duration): + Logger.log("w", "Preheat hotend not implemented in controller") + def setHeadPosition(self, printer: "PrinterOutputModel", x, y, z, speed): Logger.log("w", "Set head position not implemented in controller") From 0f0b1c6795374b7434ccf994bf554e8c88840b6e Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 18 Jan 2018 00:05:16 +0100 Subject: [PATCH 09/25] Fix getting ability to preheat from extruder --- cura/PrinterOutput/ExtruderOuputModel.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cura/PrinterOutput/ExtruderOuputModel.py b/cura/PrinterOutput/ExtruderOuputModel.py index befde28f99..d2fbabea8f 100644 --- a/cura/PrinterOutput/ExtruderOuputModel.py +++ b/cura/PrinterOutput/ExtruderOuputModel.py @@ -35,6 +35,13 @@ class ExtruderOutputModel(QObject): def getPosition(self): return self._position + # Does the printer support pre-heating the bed at all + @pyqtProperty(bool, constant=True) + def canPreHeatHotends(self): + if self._printer: + return self._printer.canPreHeatHotends + return False + @pyqtProperty(QObject, notify = activeMaterialChanged) def activeMaterial(self) -> "MaterialOutputModel": return self._active_material From 3fed44bb5e84d74fe55d53af07f180cecfc707ce Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 18 Jan 2018 00:42:41 +0100 Subject: [PATCH 10/25] Fix typo in class name --- plugins/USBPrinting/USBPrinterOutputController.py | 2 +- plugins/USBPrinting/USBPrinterOutputDevice.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/USBPrinting/USBPrinterOutputController.py b/plugins/USBPrinting/USBPrinterOutputController.py index 5640db4a63..ec47878f9c 100644 --- a/plugins/USBPrinting/USBPrinterOutputController.py +++ b/plugins/USBPrinting/USBPrinterOutputController.py @@ -10,7 +10,7 @@ if MYPY: from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel -class USBPrinterOuptutController(PrinterOutputController): +class USBPrinterOutputController(PrinterOutputController): def __init__(self, output_device): super().__init__(output_device) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index d372b54c38..b53f502d81 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -12,7 +12,7 @@ from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel from .AutoDetectBaudJob import AutoDetectBaudJob -from .USBPrinterOutputController import USBPrinterOuptutController +from .USBPrinterOutputController import USBPrinterOutputController from .avr_isp import stk500v2, intelHex from PyQt5.QtCore import pyqtSlot, pyqtSignal, pyqtProperty @@ -237,7 +237,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): container_stack = Application.getInstance().getGlobalContainerStack() num_extruders = container_stack.getProperty("machine_extruder_count", "value") # Ensure that a printer is created. - self._printers = [PrinterOutputModel(output_controller=USBPrinterOuptutController(self), number_of_extruders=num_extruders)] + self._printers = [PrinterOutputModel(output_controller=USBPrinterOutputController(self), number_of_extruders=num_extruders)] self._printers[0].updateName(container_stack.getName()) self.setConnectionState(ConnectionState.connected) self._update_thread.start() @@ -364,7 +364,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): elapsed_time = int(time() - self._print_start_time) print_job = self._printers[0].activePrintJob if print_job is None: - print_job = PrintJobOutputModel(output_controller = USBPrinterOuptutController(self), name= Application.getInstance().getPrintInformation().jobName) + print_job = PrintJobOutputModel(output_controller = USBPrinterOutputController(self), name= Application.getInstance().getPrintInformation().jobName) print_job.updateState("printing") self._printers[0].updateActivePrintJob(print_job) From 13206e1fdcc80ae05a2c30902ebd668373101710 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 18 Jan 2018 00:46:20 +0100 Subject: [PATCH 11/25] Stop preheating when a print is started or the temperature is set to 0 on the printer --- .../USBPrinting/USBPrinterOutputController.py | 91 ++++++++++++++----- 1 file changed, 68 insertions(+), 23 deletions(-) diff --git a/plugins/USBPrinting/USBPrinterOutputController.py b/plugins/USBPrinting/USBPrinterOutputController.py index ec47878f9c..b59e60c244 100644 --- a/plugins/USBPrinting/USBPrinterOutputController.py +++ b/plugins/USBPrinting/USBPrinterOutputController.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from cura.PrinterOutput.PrinterOutputController import PrinterOutputController @@ -19,10 +19,39 @@ class USBPrinterOutputController(PrinterOutputController): self._preheat_bed_timer.timeout.connect(self._onPreheatBedTimerFinished) self._preheat_printer = None - self._preheat_extruders_timer = QTimer() - self._preheat_extruders_timer.setSingleShot(True) - self._preheat_extruders_timer.timeout.connect(self._onPreheatHotendsTimerFinished) - self._preheat_extruders = set() + self._preheat_hotends_timer = QTimer() + self._preheat_hotends_timer.setSingleShot(True) + self._preheat_hotends_timer.timeout.connect(self._onPreheatHotendsTimerFinished) + self._preheat_hotends = set() + + self._output_device.printersChanged.connect(self._onPrintersChanged) + self._active_printer = None + + def _onPrintersChanged(self): + if self._active_printer: + self._active_printer.stateChanged.disconnect(self._onPrinterStateChanged) + self._active_printer.targetBedTemperatureChanged.disconnect(self._onTargetBedTemperatureChanged) + for extruder in self._active_printer.extruders: + extruder.targetHotendTemperatureChanged.disconnect(self._onTargetHotendTemperatureChanged) + + self._active_printer = self._output_device.activePrinter + if self._active_printer: + self._active_printer.stateChanged.connect(self._onPrinterStateChanged) + self._active_printer.targetBedTemperatureChanged.connect(self._onTargetBedTemperatureChanged) + for extruder in self._active_printer.extruders: + extruder.targetHotendTemperatureChanged.connect(self._onTargetHotendTemperatureChanged) + + def _onPrinterStateChanged(self): + if self._active_printer.state != "idle": + if self._preheat_bed_timer.isActive(): + self._preheat_bed_timer.stop() + self._preheat_printer.updateIsPreheating(False) + if self._preheat_hotends_timer.isActive(): + self._preheat_hotends_timer.stop() + for extruder in self._preheat_hotends: + extruder.updateIsPreheating(False) + self._preheat_hotends = set() + def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed): self._output_device.sendCommand("G91") @@ -47,9 +76,15 @@ class USBPrinterOutputController(PrinterOutputController): self._output_device.cancelPrint() pass + def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int): self._output_device.sendCommand("M140 S%s" % temperature) + def _onTargetBedTemperatureChanged(self): + if self._preheat_bed_timer.isActive() and self._preheat_printer.targetBedTemperature == 0: + self._preheat_bed_timer.stop() + self._preheat_printer.updateIsPreheating(False) + def preheatBed(self, printer: "PrinterOutputModel", temperature, duration): try: temperature = round(temperature) # The API doesn't allow floating point. @@ -64,7 +99,7 @@ class USBPrinterOutputController(PrinterOutputController): printer.updateIsPreheating(True) def cancelPreheatBed(self, printer: "PrinterOutputModel"): - self.preheatBed(printer, temperature=0, duration=0) + self.setTargetBedTemperature(printer, temperature=0) self._preheat_bed_timer.stop() printer.updateIsPreheating(False) @@ -72,23 +107,20 @@ class USBPrinterOutputController(PrinterOutputController): self.setTargetBedTemperature(self._preheat_printer, 0) self._preheat_printer.updateIsPreheating(False) + def setTargetHotendTemperature(self, printer: "PrinterOutputModel", position: int, temperature: int): self._output_device.sendCommand("M104 S%s T%s" % (temperature, position)) - def _onPreheatHotendsTimerFinished(self): - for extruder in self._preheat_extruders: - self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), 0) - self._preheat_extruders = set() - self._preheat_printer.updateIsPreheating(False) + def _onTargetHotendTemperatureChanged(self): + if not self._preheat_hotends_timer.isActive(): + return - def cancelPreheatHotend(self, extruder: "ExtruderOutputModel"): - self.preheatHotend(extruder, temperature=0, duration=0) - self._preheat_extruders_timer.stop() - try: - self._preheat_extruders.remove(extruder) - except KeyError: - pass - extruder.updateIsPreheating(False) + for extruder in self._active_printer.extruders: + if extruder in self._preheat_hotends and extruder.targetHotendTemperature == 0: + extruder.updateIsPreheating(False) + self._preheat_hotends.remove(extruder) + if not self._preheat_hotends: + self._preheat_hotends_timer.stop() def preheatHotend(self, extruder: "ExtruderOutputModel", temperature, duration): position = extruder.getPosition() @@ -103,7 +135,20 @@ class USBPrinterOutputController(PrinterOutputController): return # Got invalid values, can't pre-heat. self.setTargetHotendTemperature(extruder.getPrinter(), position, temperature=temperature) - self._preheat_extruders_timer.setInterval(duration * 1000) - self._preheat_extruders_timer.start() - self._preheat_extruders.add(extruder) - extruder.updateIsPreheating(True) \ No newline at end of file + self._preheat_hotends_timer.setInterval(duration * 1000) + self._preheat_hotends_timer.start() + self._preheat_hotends.add(extruder) + extruder.updateIsPreheating(True) + + def cancelPreheatHotend(self, extruder: "ExtruderOutputModel"): + self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), temperature=0) + if extruder in self._preheat_hotends: + extruder.updateIsPreheating(False) + self._preheat_hotends.remove(extruder) + if not self._preheat_hotends and self._preheat_hotends_timer.isActive(): + self._preheat_hotends_timer.stop() + + def _onPreheatHotendsTimerFinished(self): + for extruder in self._preheat_hotends: + self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), 0) + self._preheat_hotends = set() From f135b1675ccc427bf4825ced2da5a77f6b307874 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 18 Jan 2018 10:20:37 +0100 Subject: [PATCH 12/25] Fix disabling preheat button when printer is not idle --- resources/qml/PrinterOutput/ExtruderBox.qml | 9 ++++++--- resources/qml/PrinterOutput/HeatedBedBox.qml | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index 4aacef1a94..56c86f1034 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -130,9 +130,12 @@ Item { return false; //Not allowed to do anything. } - if (connectedPrinter.jobState == "printing" || connectedPrinter.jobState == "pre_print" || connectedPrinter.jobState == "resuming" || connectedPrinter.jobState == "pausing" || connectedPrinter.jobState == "paused" || connectedPrinter.jobState == "error" || connectedPrinter.jobState == "offline") + if (connectedPrinter.activePrinter && connectedPrinter.activePrinter.activePrintJob) { - return false; //Printer is in a state where it can't react to pre-heating. + if((["printing", "pre_print", "resuming", "pausing", "paused", "error", "offline"]).indexOf(connectedPrinter.activePrinter.activePrintJob.state) != -1) + { + return false; //Printer is in a state where it can't react to pre-heating. + } } return true; } @@ -144,7 +147,7 @@ Item anchors.bottomMargin: UM.Theme.getSize("default_margin").height width: UM.Theme.getSize("monitor_preheat_temperature_control").width height: UM.Theme.getSize("monitor_preheat_temperature_control").height - visible: extruderModel != null ? extruderModel.canPreHeatHotends && !extruderModel.isPreheating : true + visible: extruderModel != null ? enabled && extruderModel.canPreHeatHotends && !extruderModel.isPreheating : true Rectangle //Highlight of input field. { anchors.fill: parent diff --git a/resources/qml/PrinterOutput/HeatedBedBox.qml b/resources/qml/PrinterOutput/HeatedBedBox.qml index 8d1e37b23d..385977141c 100644 --- a/resources/qml/PrinterOutput/HeatedBedBox.qml +++ b/resources/qml/PrinterOutput/HeatedBedBox.qml @@ -114,9 +114,12 @@ Item { return false; //Not allowed to do anything. } - if (connectedPrinter.jobState == "printing" || connectedPrinter.jobState == "pre_print" || connectedPrinter.jobState == "resuming" || connectedPrinter.jobState == "pausing" || connectedPrinter.jobState == "paused" || connectedPrinter.jobState == "error" || connectedPrinter.jobState == "offline") + if (connectedPrinter.activePrinter && connectedPrinter.activePrinter.activePrintJob) { - return false; //Printer is in a state where it can't react to pre-heating. + if((["printing", "pre_print", "resuming", "pausing", "paused", "error", "offline"]).indexOf(connectedPrinter.activePrinter.activePrintJob.state) != -1) + { + return false; //Printer is in a state where it can't react to pre-heating. + } } return true; } @@ -128,7 +131,7 @@ Item anchors.bottomMargin: UM.Theme.getSize("default_margin").height width: UM.Theme.getSize("monitor_preheat_temperature_control").width height: UM.Theme.getSize("monitor_preheat_temperature_control").height - visible: printerModel != null ? printerModel.canPreHeatBed && !printerModel.isPreheating : true + visible: printerModel != null ? enabled && printerModel.canPreHeatBed && !printerModel.isPreheating : true Rectangle //Highlight of input field. { anchors.fill: parent From fb2a5ea28a52c99830cb49503d26d609e51cbbd5 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 18 Jan 2018 11:55:30 +0100 Subject: [PATCH 13/25] Refactor USBPrinterOutputController to reusable cura.PrinterOutput.GenericOutputController --- .../PrinterOutput/GenericOutputController.py | 2 +- plugins/USBPrinting/USBPrinterOutputDevice.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename plugins/USBPrinting/USBPrinterOutputController.py => cura/PrinterOutput/GenericOutputController.py (99%) diff --git a/plugins/USBPrinting/USBPrinterOutputController.py b/cura/PrinterOutput/GenericOutputController.py similarity index 99% rename from plugins/USBPrinting/USBPrinterOutputController.py rename to cura/PrinterOutput/GenericOutputController.py index b59e60c244..106c1e3a44 100644 --- a/plugins/USBPrinting/USBPrinterOutputController.py +++ b/cura/PrinterOutput/GenericOutputController.py @@ -10,7 +10,7 @@ if MYPY: from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel -class USBPrinterOutputController(PrinterOutputController): +class GenericOutputController(PrinterOutputController): def __init__(self, output_device): super().__init__(output_device) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index b53f502d81..52cb0d47f5 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -10,9 +10,9 @@ from UM.PluginRegistry import PluginRegistry from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel +from cura.PrinterOutput.GenericOutputController import GenericOutputController from .AutoDetectBaudJob import AutoDetectBaudJob -from .USBPrinterOutputController import USBPrinterOutputController from .avr_isp import stk500v2, intelHex from PyQt5.QtCore import pyqtSlot, pyqtSignal, pyqtProperty @@ -237,7 +237,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): container_stack = Application.getInstance().getGlobalContainerStack() num_extruders = container_stack.getProperty("machine_extruder_count", "value") # Ensure that a printer is created. - self._printers = [PrinterOutputModel(output_controller=USBPrinterOutputController(self), number_of_extruders=num_extruders)] + self._printers = [PrinterOutputModel(output_controller=GenericOutputController(self), number_of_extruders=num_extruders)] self._printers[0].updateName(container_stack.getName()) self.setConnectionState(ConnectionState.connected) self._update_thread.start() @@ -364,7 +364,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): elapsed_time = int(time() - self._print_start_time) print_job = self._printers[0].activePrintJob if print_job is None: - print_job = PrintJobOutputModel(output_controller = USBPrinterOutputController(self), name= Application.getInstance().getPrintInformation().jobName) + print_job = PrintJobOutputModel(output_controller = GenericOutputController(self), name= Application.getInstance().getPrintInformation().jobName) print_job.updateState("printing") self._printers[0].updateActivePrintJob(print_job) From bcfcc8cc7c26f8cdc85ef3d69d9ea08cdd72838f Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 19 Jan 2018 14:59:25 +0100 Subject: [PATCH 14/25] Enable setting per mesh group settings when printing One at a Time --- .../PerObjectSettingsPanel.qml | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index eb492d8de2..0976dd5df6 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -163,7 +163,16 @@ Item { id: addedSettingsModel; containerId: Cura.MachineManager.activeDefinitionId expanded: [ "*" ] - exclude: { + filter: + { + if (printSequencePropertyProvider.properties.value == "one_at_a_time") + { + return {"settable_per_meshgroup": true}; + } + return {"settable_per_mesh": true}; + } + exclude: + { var excluded_settings = [ "support_mesh", "anti_overhang_mesh", "cutting_mesh", "infill_mesh" ]; if(meshTypeSelection.model.get(meshTypeSelection.currentIndex).type == "support_mesh") @@ -451,7 +460,11 @@ Item { containerId: Cura.MachineManager.activeDefinitionId filter: { - "settable_per_mesh": true + if (printSequencePropertyProvider.properties.value == "one_at_a_time") + { + return {"settable_per_meshgroup": true}; + } + return {"settable_per_mesh": true}; } visibilityHandler: UM.SettingPreferenceVisibilityHandler {} expanded: [ "*" ] @@ -507,6 +520,16 @@ Item { storeIndex: 0 } + UM.SettingPropertyProvider + { + id: printSequencePropertyProvider + + containerStackId: Cura.MachineManager.activeMachineId + key: "print_sequence" + watchedProperties: [ "value" ] + storeIndex: 0 + } + SystemPalette { id: palette; } Component From 4d5ace4564cb1a927312665f3c63321164da8be8 Mon Sep 17 00:00:00 2001 From: Ryan Date: Sun, 11 Mar 2018 10:27:57 -0400 Subject: [PATCH 15/25] Added default material diameter to SeeMeCNC printer definitions --- resources/definitions/seemecnc_artemis.def.json | 1 + resources/definitions/seemecnc_v32.def.json | 1 + 2 files changed, 2 insertions(+) diff --git a/resources/definitions/seemecnc_artemis.def.json b/resources/definitions/seemecnc_artemis.def.json index 88a1b28de6..0b31abfa41 100644 --- a/resources/definitions/seemecnc_artemis.def.json +++ b/resources/definitions/seemecnc_artemis.def.json @@ -25,6 +25,7 @@ "machine_nozzle_size": { "default_value": 0.5 }, "machine_shape": { "default_value": "elliptic" }, "machine_width": { "default_value": 290 }, + "material_diameter": { "default_value": 1.75 }, "relative_extrusion": { "default_value": false }, "retraction_amount": { "default_value": 3.2 }, "retraction_combing": { "default_value": "off" }, diff --git a/resources/definitions/seemecnc_v32.def.json b/resources/definitions/seemecnc_v32.def.json index 5932403bc5..3f46c1540a 100644 --- a/resources/definitions/seemecnc_v32.def.json +++ b/resources/definitions/seemecnc_v32.def.json @@ -25,6 +25,7 @@ "machine_nozzle_size": { "default_value": 0.5 }, "machine_shape": { "default_value": "elliptic" }, "machine_width": { "default_value": 265 }, + "material_diameter": { "default_value": 1.75 }, "relative_extrusion": { "default_value": false }, "retraction_amount": { "default_value": 3.2 }, "retraction_combing": { "default_value": "off" }, From dee70f35f4f3a228d00c3a40a6dd643693f3a1bd Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 15 Mar 2018 11:03:27 +0100 Subject: [PATCH 16/25] Fix setting visibility when searching --- .../PerObjectSettingsPanel.qml | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index 7872908ee8..a2790dcf08 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -384,7 +384,6 @@ Item { title: catalog.i18nc("@title:window", "Select Settings to Customize for this model") width: screenScaleFactor * 360 - property string labelFilter: "" property var additional_excluded_settings onVisibilityChanged: @@ -395,11 +394,33 @@ Item { // Set skip setting, it will prevent from resetting selected mesh_type contents.model.visibilityHandler.addSkipResetSetting(meshTypeSelection.model.get(meshTypeSelection.currentIndex).type) listview.model.forceUpdate() + + updateFilter() } } + function updateFilter() + { + var new_filter = {}; + if (printSequencePropertyProvider.properties.value == "one_at_a_time") + { + new_filter["settable_per_meshgroup"] = true; + } + else + { + new_filter["settable_per_mesh"] = true; + } + + if(filterInput.text != "") + { + new_filter["i18n_label"] = "*" + filterInput.text; + } + + listview.model.filter = new_filter; + } + TextField { - id: filter + id: filterInput anchors { top: parent.top @@ -410,17 +431,7 @@ Item { placeholderText: catalog.i18nc("@label:textbox", "Filter..."); - onTextChanged: - { - if(text != "") - { - listview.model.filter = {"settable_per_mesh": true, "i18n_label": "*" + text} - } - else - { - listview.model.filter = {"settable_per_mesh": true} - } - } + onTextChanged: settingPickDialog.updateFilter() } CheckBox @@ -446,7 +457,7 @@ Item { anchors { - top: filter.bottom; + top: filterInput.bottom; left: parent.left; right: parent.right; bottom: parent.bottom; @@ -458,14 +469,6 @@ Item { { id: definitionsModel; containerId: Cura.MachineManager.activeDefinitionId - filter: - { - if (printSequencePropertyProvider.properties.value == "one_at_a_time") - { - return {"settable_per_meshgroup": true}; - } - return {"settable_per_mesh": true}; - } visibilityHandler: UM.SettingPreferenceVisibilityHandler {} expanded: [ "*" ] exclude: @@ -497,6 +500,7 @@ Item { } } } + Component.onCompleted: settingPickDialog.updateFilter() } } From 584f98cb071cc140d4fa9dd299f5820796d27a50 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 15 Mar 2018 11:27:48 +0100 Subject: [PATCH 17/25] Fix code style --- cura/PrinterOutput/ExtruderOutputModel.py | 3 ++- cura/PrinterOutput/GenericOutputController.py | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cura/PrinterOutput/ExtruderOutputModel.py b/cura/PrinterOutput/ExtruderOutputModel.py index 92b3ad6d7c..75b9cc98ac 100644 --- a/cura/PrinterOutput/ExtruderOutputModel.py +++ b/cura/PrinterOutput/ExtruderOutputModel.py @@ -20,7 +20,7 @@ class ExtruderOutputModel(QObject): extruderConfigurationChanged = pyqtSignal() isPreheatingChanged = pyqtSignal() - def __init__(self, printer: "PrinterOutputModel", position: int, parent=None): + def __init__(self, printer: "PrinterOutputModel", position, parent=None): super().__init__(parent) self._printer = printer self._position = position @@ -98,6 +98,7 @@ class ExtruderOutputModel(QObject): if self._extruder_configuration.isValid(): return self._extruder_configuration return None + def updateIsPreheating(self, pre_heating): if self._is_preheating != pre_heating: self._is_preheating = pre_heating diff --git a/cura/PrinterOutput/GenericOutputController.py b/cura/PrinterOutput/GenericOutputController.py index 106c1e3a44..a21425af92 100644 --- a/cura/PrinterOutput/GenericOutputController.py +++ b/cura/PrinterOutput/GenericOutputController.py @@ -52,7 +52,6 @@ class GenericOutputController(PrinterOutputController): extruder.updateIsPreheating(False) self._preheat_hotends = set() - def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed): self._output_device.sendCommand("G91") self._output_device.sendCommand("G0 X%s Y%s Z%s F%s" % (x, y, z, speed)) @@ -76,7 +75,6 @@ class GenericOutputController(PrinterOutputController): self._output_device.cancelPrint() pass - def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int): self._output_device.sendCommand("M140 S%s" % temperature) @@ -107,7 +105,6 @@ class GenericOutputController(PrinterOutputController): self.setTargetBedTemperature(self._preheat_printer, 0) self._preheat_printer.updateIsPreheating(False) - def setTargetHotendTemperature(self, printer: "PrinterOutputModel", position: int, temperature: int): self._output_device.sendCommand("M104 S%s T%s" % (temperature, position)) From 440a56b7fa6d4f09eb64f3969c85d4d8309b0c37 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 16:41:50 +0100 Subject: [PATCH 18/25] Fix settings export in gcode --- plugins/GCodeWriter/GCodeWriter.py | 63 ++++++++++++++++++------------ 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/plugins/GCodeWriter/GCodeWriter.py b/plugins/GCodeWriter/GCodeWriter.py index 1b3b7264a1..4b78a2a72a 100644 --- a/plugins/GCodeWriter/GCodeWriter.py +++ b/plugins/GCodeWriter/GCodeWriter.py @@ -1,17 +1,17 @@ # Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +import re # For escaping characters in the settings. +import json +import copy + from UM.Mesh.MeshWriter import MeshWriter from UM.Logger import Logger from UM.Application import Application from UM.Settings.InstanceContainer import InstanceContainer -from UM.Util import parseBool -from cura.Settings.ExtruderManager import ExtruderManager +from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch -import re #For escaping characters in the settings. -import json -import copy ## Writes g-code to a file. # @@ -45,6 +45,8 @@ class GCodeWriter(MeshWriter): def __init__(self): super().__init__() + self._application = Application.getInstance() + ## Writes the g-code for the entire scene to a stream. # # Note that even though the function accepts a collection of nodes, the @@ -94,7 +96,6 @@ class GCodeWriter(MeshWriter): return flat_container - ## Serialises a container stack to prepare it for writing at the end of the # g-code. # @@ -104,15 +105,21 @@ class GCodeWriter(MeshWriter): # \param settings A container stack to serialise. # \return A serialised string of the settings. def _serialiseSettings(self, stack): + container_registry = self._application.getContainerRegistry() + quality_manager = self._application.getQualityManager() + prefix = ";SETTING_" + str(GCodeWriter.version) + " " # The prefix to put before each line. prefix_length = len(prefix) + quality_name = stack.qualityChanges.getName() + quality_type = stack.quality.getMetaDataEntry("quality_type") container_with_profile = stack.qualityChanges if container_with_profile.getId() == "empty_quality_changes": - Logger.log("e", "No valid quality profile found, not writing settings to g-code!") - return "" + # If the global quality changes is empty, create a new one + quality_name = container_registry.uniqueName(stack.quality.getName()) + container_with_profile = quality_manager._createQualityChanges(quality_type, quality_name, stack, None) - flat_global_container = self._createFlattenedContainerInstance(stack.getTop(), container_with_profile) + flat_global_container = self._createFlattenedContainerInstance(stack.userChanges, container_with_profile) # If the quality changes is not set, we need to set type manually if flat_global_container.getMetaDataEntry("type", None) is None: flat_global_container.addMetaDataEntry("type", "quality_changes") @@ -121,41 +128,47 @@ class GCodeWriter(MeshWriter): if flat_global_container.getMetaDataEntry("quality_type", None) is None: flat_global_container.addMetaDataEntry("quality_type", stack.quality.getMetaDataEntry("quality_type", "normal")) - # Change the default defintion - default_machine_definition = "fdmprinter" - if parseBool(stack.getMetaDataEntry("has_machine_quality", "False")): - default_machine_definition = stack.getMetaDataEntry("quality_definition") - if not default_machine_definition: - default_machine_definition = stack.definition.getId() - flat_global_container.setMetaDataEntry("definition", default_machine_definition) + # Get the machine definition ID for quality profiles + machine_definition_id_for_quality = getMachineDefinitionIDForQualitySearch(stack.definition) + flat_global_container.setMetaDataEntry("definition", machine_definition_id_for_quality) serialized = flat_global_container.serialize() data = {"global_quality": serialized} - for extruder in sorted(stack.extruders.values(), key = lambda k: k.getMetaDataEntry("position")): + all_setting_keys = set(flat_global_container.getAllKeys()) + for extruder in sorted(stack.extruders.values(), key = lambda k: int(k.getMetaDataEntry("position"))): extruder_quality = extruder.qualityChanges if extruder_quality.getId() == "empty_quality_changes": - Logger.log("w", "No extruder quality profile found, not writing quality for extruder %s to file!", extruder.getId()) - continue - flat_extruder_quality = self._createFlattenedContainerInstance(extruder.getTop(), extruder_quality) + # Same story, if quality changes is empty, create a new one + quality_name = container_registry.uniqueName(stack.quality.getName()) + extruder_quality = quality_manager._createQualityChanges(quality_type, quality_name, stack, None) + + flat_extruder_quality = self._createFlattenedContainerInstance(extruder.userChanges, extruder_quality) # If the quality changes is not set, we need to set type manually if flat_extruder_quality.getMetaDataEntry("type", None) is None: flat_extruder_quality.addMetaDataEntry("type", "quality_changes") # Ensure that extruder is set. (Can happen if we have empty quality changes). - if flat_extruder_quality.getMetaDataEntry("extruder", None) is None: - flat_extruder_quality.addMetaDataEntry("extruder", extruder.getBottom().getId()) + if flat_extruder_quality.getMetaDataEntry("position", None) is None: + flat_extruder_quality.addMetaDataEntry("position", extruder.getMetaDataEntry("position")) # Ensure that quality_type is set. (Can happen if we have empty quality changes). if flat_extruder_quality.getMetaDataEntry("quality_type", None) is None: flat_extruder_quality.addMetaDataEntry("quality_type", extruder.quality.getMetaDataEntry("quality_type", "normal")) - # Change the default defintion - flat_extruder_quality.setMetaDataEntry("definition", default_machine_definition) + # Change the default definition + flat_extruder_quality.setMetaDataEntry("definition", machine_definition_id_for_quality) extruder_serialized = flat_extruder_quality.serialize() data.setdefault("extruder_quality", []).append(extruder_serialized) + all_setting_keys.update(set(flat_extruder_quality.getAllKeys())) + + # Check if there is any profiles + if not all_setting_keys: + Logger.log("i", "No custom settings found, not writing settings to g-code.") + return "" + json_string = json.dumps(data) # Escape characters that have a special meaning in g-code comments. @@ -169,5 +182,5 @@ class GCodeWriter(MeshWriter): # Lines have 80 characters, so the payload of each line is 80 - prefix. for pos in range(0, len(escaped_string), 80 - prefix_length): - result += prefix + escaped_string[pos : pos + 80 - prefix_length] + "\n" + result += prefix + escaped_string[pos: pos + 80 - prefix_length] + "\n" return result From 9de114c73ab5976466cc222851666525c054bd6d Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 16:47:51 +0100 Subject: [PATCH 19/25] Simplify discardOrKeepProfileChangesClosed() --- cura/CuraApplication.py | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 1b5de89c2b..6056745c75 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -451,27 +451,18 @@ class CuraApplication(QtApplication): @pyqtSlot(str) def discardOrKeepProfileChangesClosed(self, option): + global_stack = self.getGlobalContainerStack() if option == "discard": - global_stack = self.getGlobalContainerStack() - for extruder in self._extruder_manager.getMachineExtruders(global_stack.getId()): - extruder.getTop().clear() - global_stack.getTop().clear() + for extruder in global_stack.extruders.values(): + extruder.userChanges.clear() + global_stack.userChanges.clear() # if the user decided to keep settings then the user settings should be re-calculated and validated for errors # before slicing. To ensure that slicer uses right settings values elif option == "keep": - global_stack = self.getGlobalContainerStack() - for extruder in self._extruder_manager.getMachineExtruders(global_stack.getId()): - user_extruder_container = extruder.getTop() - if user_extruder_container: - user_extruder_container.update() - - user_global_container = global_stack.getTop() - if user_global_container: - user_global_container.update() - - # notify listeners that quality has changed (after user selected discard or keep) - self.getMachineManager().activeQualityChanged.emit() + for extruder in global_stack.extruders.values(): + extruder.userChanges.update() + global_stack.userChanges.update() @pyqtSlot(int) def messageBoxClosed(self, button): From 40ba06f011eccbe0f12d1b42beccc4dfe83f7cb2 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 15 Mar 2018 16:45:04 +0100 Subject: [PATCH 20/25] Fix output type of BQ Hephestos That application/x-code may actually be the XCode application or something? Whatever, it should be x-gcode... --- resources/definitions/bq_hephestos_xl.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/bq_hephestos_xl.def.json b/resources/definitions/bq_hephestos_xl.def.json index 75b756c71e..08be4b8d34 100644 --- a/resources/definitions/bq_hephestos_xl.def.json +++ b/resources/definitions/bq_hephestos_xl.def.json @@ -6,7 +6,7 @@ "visible": true, "manufacturer": "BQ", "author": "BQ", - "file_formats": "text/x-code", + "file_formats": "text/x-gcode", "platform": "bq_hephestos_platform.stl", "platform_offset": [ 0, -82, 0] }, From b0f7a5b3588966ae088df610626b1578c17e9540 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 15 Mar 2018 16:52:16 +0100 Subject: [PATCH 21/25] Fix translation of there being no file formats available This entry said that it had a context, but it had none. As a result, the whole string was seen as a context. --- .../RemovableDriveOutputDevice/RemovableDriveOutputDevice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py b/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py index ff930e2c31..1bfdbd4117 100644 --- a/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py +++ b/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py @@ -60,7 +60,7 @@ class RemovableDriveOutputDevice(OutputDevice): if len(file_formats) == 0: Logger.log("e", "There are no file formats available to write with!") - raise OutputDeviceError.WriteRequestFailedError(catalog.i18nc("There are no file formats available to write with!")) + raise OutputDeviceError.WriteRequestFailedError(catalog.i18nc("@info:status", "There are no file formats available to write with!")) # Just take the first file format available. if file_handler is not None: From b8ab623c803f343e09e1f1a69412e54c2ca13ad5 Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Thu, 15 Mar 2018 16:54:39 +0100 Subject: [PATCH 22/25] Fix: Infill slider did not work at first Cura start CURA-5071 --- resources/qml/SidebarSimple.qml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index 41ecb529eb..c02337d1f5 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -594,7 +594,9 @@ Item // Update value only if the Recomended mode is Active, // Otherwise if I change the value in the Custom mode the Recomended view will try to repeat // same operation - if (UM.Preferences.getValue("cura/active_mode") == 0) { + var active_mode = UM.Preferences.getValue("cura/active_mode") + + if (active_mode == 0 || active_mode == "simple") { Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", roundedSliderValue) } } From 3bb0a481f1a4e2ba26d494fc803d5394877d3ac8 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 17:00:45 +0100 Subject: [PATCH 23/25] Simplify default quality reset --- cura/Settings/MachineManager.py | 9 +++++++++ resources/qml/SidebarSimple.qml | 15 ++------------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 50c3c53734..b614e1e1e8 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1269,6 +1269,15 @@ class MachineManager(QObject): if not no_dialog and self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: self._application.discardOrKeepProfileChanges() + @pyqtSlot() + def clearQualityChangesGroup(self): + with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): + self._setQualityGroup(self._current_quality_group) + + # See if we need to show the Discard or Keep changes screen + if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: + self._application.discardOrKeepProfileChanges() + @pyqtProperty(QObject, fset = setQualityChangesGroup, notify = activeQualityChangesGroupChanged) def activeQualityChangesGroup(self): return self._current_quality_changes_group diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index c02337d1f5..a8af3fc3dd 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -19,7 +19,7 @@ Item property Action configureSettings; property variant minimumPrintTime: PrintInformation.minimumPrintTime; property variant maximumPrintTime: PrintInformation.maximumPrintTime; - property bool settingsEnabled: Cura.ExtruderManager.activeExtruderStackId || extrudersEnabledCount.properties.value == 1 + property bool settingsEnabled: extrudersEnabledCount.properties.value == 1 Component.onCompleted: PrintInformation.enabled = true Component.onDestruction: PrintInformation.enabled = false @@ -474,18 +474,7 @@ Item onClicked: { // if the current profile is user-created, switch to a built-in quality - if (Cura.SimpleModeSettingsManager.isProfileUserCreated) - { - if (Cura.QualityProfilesDropDownMenuModel.rowCount() > 0) - { - var item = Cura.QualityProfilesDropDownMenuModel.getItem(0); - Cura.MachineManager.activeQualityGroup = item.quality_group; - } - } - if (Cura.SimpleModeSettingsManager.isProfileCustomized) - { - discardOrKeepProfileChangesDialog.show() - } + Cura.MachineManager.clearQualityChangesGroup() } onEntered: { From f8709b6d1af90483c7216cfe28635a4e633f1079 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 15 Mar 2018 17:02:36 +0100 Subject: [PATCH 24/25] CURA-4400 improved enabled / disabled extruder visually, improved colors of dark theme --- resources/qml/SidebarHeader.qml | 44 ++++++++++++++++++++------- resources/themes/cura-dark/theme.json | 6 ++-- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 92af6e9cc9..7baf13ca97 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -186,22 +186,34 @@ Column { background: Item { - Rectangle + function buttonBackgroundColor(index) { - anchors.fill: parent - border.width: control.checked ? UM.Theme.getSize("default_lining").width * 2 : UM.Theme.getSize("default_lining").width - border.color: (control.checked || 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.checked || control.pressed) ? UM.Theme.getColor("action_button_active") : - control.hovered ? UM.Theme.getColor("action_button_hovered") : - UM.Theme.getColor("action_button") - Behavior on color { ColorAnimation { duration: 50; } } + var extruder = Cura.MachineManager.getExtruder(index) + if (extruder.isEnabled) { + return (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active") : + control.hovered ? UM.Theme.getColor("action_button_hovered") : + UM.Theme.getColor("action_button") + } else { + return UM.Theme.getColor("action_button_disabled") + } + } + + function buttonBorderColor(index) + { + var extruder = Cura.MachineManager.getExtruder(index) + if (extruder.isEnabled) { + return (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_border") : + control.hovered ? UM.Theme.getColor("action_button_hovered_border") : + UM.Theme.getColor("action_button_border") + } else { + return UM.Theme.getColor("action_button_disabled_border") + } } function buttonColor(index) { var extruder = Cura.MachineManager.getExtruder(index); - if (extruder.isEnabled) { + if (extruder.isEnabled) + { return ( control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_text") : control.hovered ? UM.Theme.getColor("action_button_hovered_text") : @@ -211,10 +223,20 @@ Column } } + Rectangle + { + anchors.fill: parent + border.width: control.checked ? UM.Theme.getSize("default_lining").width * 2 : UM.Theme.getSize("default_lining").width + border.color: buttonBorderColor(index) + color: buttonBackgroundColor(index) + Behavior on color { ColorAnimation { duration: 50; } } + } + Item { id: extruderButtonFace anchors.centerIn: parent + width: { var extruderTextWidth = extruderStaticText.visible ? extruderStaticText.width : 0; var iconWidth = extruderIconItem.width; diff --git a/resources/themes/cura-dark/theme.json b/resources/themes/cura-dark/theme.json index 80a5eec09c..5fbe36fcdb 100644 --- a/resources/themes/cura-dark/theme.json +++ b/resources/themes/cura-dark/theme.json @@ -84,16 +84,16 @@ "tab_background": [39, 44, 48, 255], "action_button": [39, 44, 48, 255], - "action_button_text": [255, 255, 255, 101], + "action_button_text": [255, 255, 255, 200], "action_button_border": [255, 255, 255, 30], "action_button_hovered": [39, 44, 48, 255], "action_button_hovered_text": [255, 255, 255, 255], "action_button_hovered_border": [255, 255, 255, 30], "action_button_active": [39, 44, 48, 30], "action_button_active_text": [255, 255, 255, 255], - "action_button_active_border": [255, 255, 255, 30], + "action_button_active_border": [255, 255, 255, 100], "action_button_disabled": [39, 44, 48, 255], - "action_button_disabled_text": [255, 255, 255, 101], + "action_button_disabled_text": [255, 255, 255, 80], "action_button_disabled_border": [255, 255, 255, 30], "scrollbar_background": [39, 44, 48, 0], From f14ddb8711ac1cdcb91aa33cc82e7ca890ed2c14 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 17:08:44 +0100 Subject: [PATCH 25/25] Fix reset to default quality --- cura/Settings/MachineManager.py | 8 +++----- cura/Settings/SimpleModeSettingsManager.py | 3 ++- resources/qml/SidebarSimple.qml | 3 +-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index b614e1e1e8..9619329e59 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1270,13 +1270,11 @@ class MachineManager(QObject): self._application.discardOrKeepProfileChanges() @pyqtSlot() - def clearQualityChangesGroup(self): + def resetToUseDefaultQuality(self): with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): self._setQualityGroup(self._current_quality_group) - - # See if we need to show the Discard or Keep changes screen - if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: - self._application.discardOrKeepProfileChanges() + for stack in [self._global_container_stack] + list(self._global_container_stack.extruders.values()): + stack.userChanges.clear() @pyqtProperty(QObject, fset = setQualityChangesGroup, notify = activeQualityChangesGroupChanged) def activeQualityChangesGroup(self): diff --git a/cura/Settings/SimpleModeSettingsManager.py b/cura/Settings/SimpleModeSettingsManager.py index 867a21702c..a337d8b04e 100644 --- a/cura/Settings/SimpleModeSettingsManager.py +++ b/cura/Settings/SimpleModeSettingsManager.py @@ -16,7 +16,8 @@ class SimpleModeSettingsManager(QObject): self._is_profile_user_created = False # True when profile was custom created by user self._machine_manager.activeStackValueChanged.connect(self._updateIsProfileCustomized) - self._machine_manager.activeQualityChanged.connect(self._updateIsProfileUserCreated) + self._machine_manager.activeQualityGroupChanged.connect(self._updateIsProfileUserCreated) + self._machine_manager.activeQualityChangesGroupChanged.connect(self._updateIsProfileUserCreated) # update on create as the activeQualityChanged signal is emitted before this manager is created when Cura starts self._updateIsProfileCustomized() diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index a8af3fc3dd..aa6f3ce1de 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -111,7 +111,6 @@ Item // Set selected value if (Cura.MachineManager.activeQualityType == qualityItem.quality_type) { - // set to -1 when switching to user created profile so all ticks are clickable if (Cura.SimpleModeSettingsManager.isProfileUserCreated) { qualityModel.qualitySliderActiveIndex = -1 @@ -474,7 +473,7 @@ Item onClicked: { // if the current profile is user-created, switch to a built-in quality - Cura.MachineManager.clearQualityChangesGroup() + Cura.MachineManager.resetToUseDefaultQuality() } onEntered: {