diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 1c9a0708fd..4e55528f5d 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -956,14 +956,14 @@ class BuildVolume(SceneNode): if adhesion_type == "skirt": skirt_distance = self._getSettingFromAdhesionExtruder("skirt_gap") skirt_line_count = self._getSettingFromAdhesionExtruder("skirt_line_count") - bed_adhesion_size = skirt_distance + (skirt_line_count * self._getSettingFromAdhesionExtruder("skirt_brim_line_width")) * self._getSettingFromAdhesionExtruder("initial_layer_line_width_factor") / 100.0 + bed_adhesion_size = skirt_distance + (self._getSettingFromAdhesionExtruder("skirt_brim_line_width") * skirt_line_count) * self._getSettingFromAdhesionExtruder("initial_layer_line_width_factor") / 100.0 if len(used_extruders) > 1: for extruder_stack in used_extruders: bed_adhesion_size += extruder_stack.getProperty("skirt_brim_line_width", "value") * extruder_stack.getProperty("initial_layer_line_width_factor", "value") / 100.0 #We don't create an additional line for the extruder we're printing the skirt with. bed_adhesion_size -= self._getSettingFromAdhesionExtruder("skirt_brim_line_width", "value") * self._getSettingFromAdhesionExtruder("initial_layer_line_width_factor", "value") / 100.0 elif adhesion_type == "brim": - bed_adhesion_size = self._getSettingFromAdhesionExtruder("brim_line_count") * self._getSettingFromAdhesionExtruder("skirt_brim_line_width") * self._getSettingFromAdhesionExtruder("initial_layer_line_width_factor") / 100.0 + bed_adhesion_size = self._getSettingFromAdhesionExtruder("skirt_brim_line_width") * self._getSettingFromAdhesionExtruder("brim_line_count") * self._getSettingFromAdhesionExtruder("initial_layer_line_width_factor") / 100.0 if self._global_container_stack.getProperty("machine_extruder_count", "value") > 1: for extruder_stack in used_extruders: bed_adhesion_size += extruder_stack.getProperty("skirt_brim_line_width", "value") * extruder_stack.getProperty("initial_layer_line_width_factor", "value") / 100.0 diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index 2b7a35995b..209d95d616 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015 Ultimaker B.V. +# Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty @@ -51,20 +51,7 @@ class PrintInformation(QObject): def __init__(self, parent = None): super().__init__(parent) - self._current_print_time = Duration(None, self) - self._print_times_per_feature = { - "none": Duration(None, self), - "inset_0": Duration(None, self), - "inset_x": Duration(None, self), - "skin": Duration(None, self), - "support": Duration(None, self), - "skirt": Duration(None, self), - "infill": Duration(None, self), - "support_infill": Duration(None, self), - "travel": Duration(None, self), - "retract": Duration(None, self), - "support_interface": Duration(None, self) - } + self.initializeCuraMessagePrintTimeProperties() self._material_lengths = [] self._material_weights = [] @@ -91,6 +78,33 @@ class PrintInformation(QObject): self._material_amounts = [] + + # Crate cura message translations and using translation keys initialize empty time Duration object for total time + # and time for each feature + def initializeCuraMessagePrintTimeProperties(self): + self._current_print_time = Duration(None, self) + + self._print_time_message_translations = { + "inset_0": catalog.i18nc("@tooltip", "Outer Wall"), + "inset_x": catalog.i18nc("@tooltip", "Inner Walls"), + "skin": catalog.i18nc("@tooltip", "Skin"), + "infill": catalog.i18nc("@tooltip", "Infill"), + "support_infill": catalog.i18nc("@tooltip", "Support Infill"), + "support_interface": catalog.i18nc("@tooltip", "Support Interface"), + "support": catalog.i18nc("@tooltip", "Support"), + "skirt": catalog.i18nc("@tooltip", "Skirt"), + "travel": catalog.i18nc("@tooltip", "Travel"), + "retract": catalog.i18nc("@tooltip", "Retractions"), + "none": catalog.i18nc("@tooltip", "Other") + } + + self._print_time_message_values = {} + + # Full fill message values using keys from _print_time_message_translations + for key in sorted(self._print_time_message_translations.keys()): + self._print_time_message_values[key] = Duration(None, self) + + currentPrintTimeChanged = pyqtSignal() preSlicedChanged = pyqtSignal() @@ -107,10 +121,6 @@ class PrintInformation(QObject): def currentPrintTime(self): return self._current_print_time - @pyqtProperty("QVariantMap", notify = currentPrintTimeChanged) - def printTimesPerFeature(self): - return self._print_times_per_feature - materialLengthsChanged = pyqtSignal() @pyqtProperty("QVariantList", notify = materialLengthsChanged) @@ -129,22 +139,28 @@ class PrintInformation(QObject): def materialCosts(self): return self._material_costs - def _onPrintDurationMessage(self, time_per_feature, material_amounts): - total_time = 0 - for feature, time in time_per_feature.items(): - if time != time: # Check for NaN. Engine can sometimes give us weird values. - self._print_times_per_feature[feature].setDuration(0) - Logger.log("w", "Received NaN for print duration message") - continue - total_time += time - self._print_times_per_feature[feature].setDuration(time) - self._current_print_time.setDuration(total_time) + def _onPrintDurationMessage(self, print_time, material_amounts): + self._updateTotalPrintTimePerFeature(print_time) self.currentPrintTimeChanged.emit() self._material_amounts = material_amounts self._calculateInformation() + def _updateTotalPrintTimePerFeature(self, print_time): + total_estimated_time = 0 + + for feature, time in print_time.items(): + if time != time: # Check for NaN. Engine can sometimes give us weird values. + self._print_time_message_values.get(feature).setDuration(0) + Logger.log("w", "Received NaN for print duration message") + continue + + total_estimated_time += time + self._print_time_message_values.get(feature).setDuration(time) + + self._current_print_time.setDuration(total_estimated_time) + def _calculateInformation(self): if Application.getInstance().getGlobalContainerStack() is None: return @@ -294,3 +310,23 @@ class PrintInformation(QObject): ## Utility method that strips accents from characters (eg: รข -> a) def _stripAccents(self, str): return ''.join(char for char in unicodedata.normalize('NFD', str) if unicodedata.category(char) != 'Mn') + + @pyqtSlot(result = "QVariantMap") + def getFeaturePrintTimes(self): + result = {} + for feature, time in self._print_time_message_values.items(): + if feature in self._print_time_message_translations: + result[self._print_time_message_translations[feature]] = time + else: + result[feature] = time + return result + + # Simulate message with zero time duration + def setToZeroPrintInformation(self): + temp_message = {} + for key in self._print_time_message_values.keys(): + temp_message[key] = 0 + + temp_material_amounts = [0] + self._onPrintDurationMessage(temp_message, temp_material_amounts) + diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index ea1f8c39b4..fc443daaa3 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015 Ultimaker B.V. +# Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. from UM.Backend.Backend import Backend, BackendState @@ -196,19 +196,7 @@ class CuraEngineBackend(QObject, Backend): Logger.log("w", "Slice unnecessary, nothing has changed that needs reslicing.") return - self.printDurationMessage.emit({ - "none": 0, - "inset_0": 0, - "inset_x": 0, - "skin": 0, - "support": 0, - "skirt": 0, - "infill": 0, - "support_infill": 0, - "travel": 0, - "retract": 0, - "support_interface": 0 - }, [0]) + Application.getInstance().getPrintInformation().setToZeroPrintInformation() self._stored_layer_data = [] self._stored_optimized_layer_data = [] @@ -514,29 +502,6 @@ class CuraEngineBackend(QObject, Backend): def _onGCodePrefixMessage(self, message): self._scene.gcode_list.insert(0, message.data.decode("utf-8", "replace")) - ## Called when a print time message is received from the engine. - # - # \param message The protobuf message containing the print time per feature and - # material amount per extruder - def _onPrintTimeMaterialEstimates(self, message): - material_amounts = [] - for index in range(message.repeatedMessageCount("materialEstimates")): - material_amounts.append(message.getRepeatedMessage("materialEstimates", index).material_amount) - feature_times = { - "none": message.time_none, - "inset_0": message.time_inset_0, - "inset_x": message.time_inset_x, - "skin": message.time_skin, - "support": message.time_support, - "skirt": message.time_skirt, - "infill": message.time_infill, - "support_infill": message.time_support_infill, - "travel": message.time_travel, - "retract": message.time_retract, - "support_interface": message.time_support_interface - } - self.printDurationMessage.emit(feature_times, material_amounts) - ## Creates a new socket connection. def _createSocket(self): super()._createSocket(os.path.abspath(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "Cura.proto"))) @@ -555,6 +520,38 @@ class CuraEngineBackend(QObject, Backend): else: self._change_timer.start() + ## Called when a print time message is received from the engine. + # + # \param message The protobuf message containing the print time per feature and + # material amount per extruder + def _onPrintTimeMaterialEstimates(self, message): + material_amounts = [] + for index in range(message.repeatedMessageCount("materialEstimates")): + material_amounts.append(message.getRepeatedMessage("materialEstimates", index).material_amount) + + times = self._parseMessagePrintTimes(message) + self.printDurationMessage.emit(times, material_amounts) + + ## Called for parsing message to retrieve estimated time per feature + # + # \param message The protobuf message containing the print time per feature + def _parseMessagePrintTimes(self, message): + + result = { + "inset_0": message.time_inset_0, + "inset_x": message.time_inset_x, + "skin": message.time_skin, + "infill": message.time_infill, + "support_infill": message.time_support_infill, + "support_interface": message.time_support_interface, + "support": message.time_support, + "skirt": message.time_skirt, + "travel": message.time_travel, + "retract": message.time_retract, + "none": message.time_none + } + return result + ## Called when the back-end connects to the front-end. def _onBackendConnected(self): if self._restart: diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index ba357f40a5..ba1a05b828 100755 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -26,7 +26,6 @@ Rectangle property bool monitoringPrint: false property variant printDuration: PrintInformation.currentPrintTime - property variant printDurationPerFeature: PrintInformation.printTimesPerFeature property variant printMaterialLengths: PrintInformation.materialLengths property variant printMaterialWeights: PrintInformation.materialWeights property variant printMaterialCosts: PrintInformation.materialCosts @@ -388,54 +387,60 @@ Rectangle anchors.bottom: parent.bottom anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width anchors.bottomMargin: UM.Theme.getSize("sidebar_margin").height - height: childrenRect.height + height: timeDetails.height + timeSpecDescription.height + lengthSpec.height visible: !monitoringPrint - UM.TooltipArea + Text { - id: timeSpecPerFeatureTooltipArea - width: timeSpec.width - height: timeSpec.height + id: timeDetails anchors.left: parent.left anchors.bottom: timeSpecDescription.top + font: UM.Theme.getFont("large") + color: UM.Theme.getColor("text_subtext") + text: (!base.printDuration || !base.printDuration.valid) ? catalog.i18nc("@label", "00h 00min") : base.printDuration.getDisplayString(UM.DurationFormat.Short) - text: { - var order = ["inset_0", "inset_x", "skin", "infill", "support_infill", "support_interface", "support", "travel", "retract", "none"]; - var visible_names = { - "inset_0": catalog.i18nc("@tooltip", "Outer Wall"), - "inset_x": catalog.i18nc("@tooltip", "Inner Walls"), - "skin": catalog.i18nc("@tooltip", "Skin"), - "infill": catalog.i18nc("@tooltip", "Infill"), - "support_infill": catalog.i18nc("@tooltip", "Support Infill"), - "support_interface": catalog.i18nc("@tooltip", "Support Interface"), - "support": catalog.i18nc("@tooltip", "Support"), - "travel": catalog.i18nc("@tooltip", "Travel"), - "retract": catalog.i18nc("@tooltip", "Retractions"), - "none": catalog.i18nc("@tooltip", "Other") - }; - var result = ""; - for(var feature in order) + MouseArea + { + id: infillMouseArea + anchors.fill: parent + hoverEnabled: true + //enabled: base.settingsEnabled + + onEntered: { - feature = order[feature]; - if(base.printDurationPerFeature[feature] && base.printDurationPerFeature[feature].totalSeconds > 0) + + if(base.printDuration.valid && !base.printDuration.isTotalDurationZero) { - result += "
" + visible_names[feature] + ": " + base.printDurationPerFeature[feature].getDisplayString(UM.DurationFormat.Short); + var print_time = PrintInformation.getFeaturePrintTimes() + + var valid_data = []; + for(var feature in print_time) + { + if(!print_time[feature].isTotalDurationZero) + { + valid_data.push(feature + ": " + print_time[feature].getDisplayString(UM.DurationFormat.Short)) + } + } + + var output = "" + for(var counter = 0; counter < valid_data.length; counter++) + { + output += valid_data[counter]; + if(counter + 1 != valid_data.length) + output += "\n" + } + + var content = catalog.i18nc("@tooltip",output) + base.showTooltip(parent, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), content) } } - result = result.replace(/^\/, ""); // remove newline before first item - return result; - } - - Text - { - id: timeSpec - anchors.left: parent.left - anchors.bottom: parent.bottom - font: UM.Theme.getFont("large") - color: UM.Theme.getColor("text_subtext") - text: (!base.printDuration || !base.printDuration.valid) ? catalog.i18nc("@label", "00h 00min") : base.printDuration.getDisplayString(UM.DurationFormat.Short) + onExited: + { + base.hideTooltip(); + } } } + Text { id: timeSpecDescription