From 34f4417e16d36c8c121a9f5d9269cf27b48c59cd Mon Sep 17 00:00:00 2001 From: Alexander Gee Date: Fri, 8 May 2020 19:22:40 -0500 Subject: [PATCH 01/28] Add PostProcessingPlugin script DisplayPercentCompleteOnLCD --- .../scripts/DisplayPercentCompleteOnLCD.py | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 plugins/PostProcessingPlugin/scripts/DisplayPercentCompleteOnLCD.py diff --git a/plugins/PostProcessingPlugin/scripts/DisplayPercentCompleteOnLCD.py b/plugins/PostProcessingPlugin/scripts/DisplayPercentCompleteOnLCD.py new file mode 100644 index 0000000000..41cb390f7b --- /dev/null +++ b/plugins/PostProcessingPlugin/scripts/DisplayPercentCompleteOnLCD.py @@ -0,0 +1,93 @@ +# Cura PostProcessingPlugin +# Author: Alexander Gee +# Date: May 3, 2020 +# Modified: May 3, 2020 + +# Description: This plugin will write the percent of time complete on the LCD using Marlin's M73 command. + + +from ..Script import Script + +import re + +class DisplayPercentCompleteOnLCD(Script): + + def __init__(self): + super().__init__() + + def getSettingDataString(self): + return """{ + "name":"Display Percent Complete on LCD", + "key":"DisplayPercentCompleteOnLCD", + "metadata": {}, + "version": 2, + "settings": + { + "TurnOn": + { + "label": "Enable", + "description": "When enabled, It will write the percent of time complete on the LCD using Marlin's M73 command.", + "type": "bool", + "default_value": false + } + } + }""" + + # Get the time value from a line as a float. + # Example line ;TIME_ELAPSED:1234.6789 or ;TIME:1337 + def getTimeValue(self, line): + list_split = re.split(":", line) # Split at ":" so we can get the numerical value + return float(list_split[1]) # Convert the numerical portion to a float + + def execute(self, data): + if self.getSettingValueByKey("TurnOn"): + total_time = -1 + previous_layer_end_percentage = 0 + for layer in data: + layer_index = data.index(layer) + lines = layer.split("\n") + + for line in lines: + if line.startswith(";TIME:") and total_time == -1: + # This line represents the total time required to print the gcode + total_time = self.getTimeValue(line) + # Emit 0 percent to sure Marlin knows we are overriding the completion percentage + lines.insert(lines.index(line),"M73 P0") + + elif line.startswith(";TIME_ELAPSED:"): + # We've found one of the time elapsed values which are added at the end of layers + + # If total_time was not already found then noop + if (total_time == -1): + continue + + # Calculate percentage value this layer ends at + layer_end_percentage = int((self.getTimeValue(line) / total_time) * 100) + + # Figure out how many percent of the total time is spent in this layer + layer_percentage_delta = layer_end_percentage - previous_layer_end_percentage + + # If this layer represents less than 1 percent then we don't need to emit anything, continue to the next layer + if (layer_percentage_delta == 0): + continue + + # Grab the index of the current line and figure out how many lines represent one percent + step = lines.index(line) / layer_percentage_delta + + for percentage in range(1, layer_percentage_delta + 1): + # We add the percentage value here as while processing prior lines we will have inserted + # percentage lines before the current one. Failing to do this will upset the spacing + line_index = int((percentage * step) + percentage) + + # Due to integer truncation of the total time value in the gcode the percentage we + # calculate may slightly exceed 100, as that is not valid we cap the value here + output = min(percentage + previous_layer_end_percentage, 100) + + # Now insert the sanitized percentage into the GCODE + lines.insert(line_index, "M73 P{}".format(output)) + + previous_layer_end_percentage = layer_end_percentage + + # Join up the lines for this layer again and store them in the data array + data[layer_index] = "\n".join(lines) + return data From 83e259cd93abe7fa42025b05096bd5d02aa9d0e4 Mon Sep 17 00:00:00 2001 From: Alexander Gee Date: Wed, 13 May 2020 23:35:39 -0500 Subject: [PATCH 02/28] Rename to DisplayProgressOnLCD --- ...ayRemainingTimeOnLCD.py => DisplayProgressOnLCD.py} | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) rename plugins/PostProcessingPlugin/scripts/{DisplayRemainingTimeOnLCD.py => DisplayProgressOnLCD.py} (95%) diff --git a/plugins/PostProcessingPlugin/scripts/DisplayRemainingTimeOnLCD.py b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py similarity index 95% rename from plugins/PostProcessingPlugin/scripts/DisplayRemainingTimeOnLCD.py rename to plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py index 7d9af10925..8262061134 100644 --- a/plugins/PostProcessingPlugin/scripts/DisplayRemainingTimeOnLCD.py +++ b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py @@ -1,7 +1,7 @@ # Cura PostProcessingPlugin -# Author: Mathias Lyngklip Kjeldgaard +# Author: Mathias Lyngklip Kjeldgaard, Alexander Gee # Date: July 31, 2019 -# Modified: November 26, 2019 +# Modified: May 13, 2020 # Description: This plugin displayes the remaining time on the LCD of the printer # using the estimated print-time generated by Cura. @@ -15,7 +15,7 @@ import re import datetime -class DisplayRemainingTimeOnLCD(Script): +class DisplayProgressOnLCD(Script): def __init__(self): super().__init__() @@ -23,8 +23,8 @@ class DisplayRemainingTimeOnLCD(Script): def getSettingDataString(self): return """{ - "name":"Display Remaining Time on LCD", - "key":"DisplayRemainingTimeOnLCD", + "name":"Display Progress on LCD", + "key":"DisplayProgressOnLCD", "metadata": {}, "version": 2, "settings": From 0daccce7b1484228d499b7d702ffa4eca97aca21 Mon Sep 17 00:00:00 2001 From: Alexander Gee Date: Wed, 13 May 2020 23:36:49 -0500 Subject: [PATCH 03/28] Incorperate percentage and time remaining scripts --- .../scripts/DisplayPercentCompleteOnLCD.py | 93 ------------- .../scripts/DisplayProgressOnLCD.py | 131 +++++++++++------- 2 files changed, 81 insertions(+), 143 deletions(-) delete mode 100644 plugins/PostProcessingPlugin/scripts/DisplayPercentCompleteOnLCD.py diff --git a/plugins/PostProcessingPlugin/scripts/DisplayPercentCompleteOnLCD.py b/plugins/PostProcessingPlugin/scripts/DisplayPercentCompleteOnLCD.py deleted file mode 100644 index 41cb390f7b..0000000000 --- a/plugins/PostProcessingPlugin/scripts/DisplayPercentCompleteOnLCD.py +++ /dev/null @@ -1,93 +0,0 @@ -# Cura PostProcessingPlugin -# Author: Alexander Gee -# Date: May 3, 2020 -# Modified: May 3, 2020 - -# Description: This plugin will write the percent of time complete on the LCD using Marlin's M73 command. - - -from ..Script import Script - -import re - -class DisplayPercentCompleteOnLCD(Script): - - def __init__(self): - super().__init__() - - def getSettingDataString(self): - return """{ - "name":"Display Percent Complete on LCD", - "key":"DisplayPercentCompleteOnLCD", - "metadata": {}, - "version": 2, - "settings": - { - "TurnOn": - { - "label": "Enable", - "description": "When enabled, It will write the percent of time complete on the LCD using Marlin's M73 command.", - "type": "bool", - "default_value": false - } - } - }""" - - # Get the time value from a line as a float. - # Example line ;TIME_ELAPSED:1234.6789 or ;TIME:1337 - def getTimeValue(self, line): - list_split = re.split(":", line) # Split at ":" so we can get the numerical value - return float(list_split[1]) # Convert the numerical portion to a float - - def execute(self, data): - if self.getSettingValueByKey("TurnOn"): - total_time = -1 - previous_layer_end_percentage = 0 - for layer in data: - layer_index = data.index(layer) - lines = layer.split("\n") - - for line in lines: - if line.startswith(";TIME:") and total_time == -1: - # This line represents the total time required to print the gcode - total_time = self.getTimeValue(line) - # Emit 0 percent to sure Marlin knows we are overriding the completion percentage - lines.insert(lines.index(line),"M73 P0") - - elif line.startswith(";TIME_ELAPSED:"): - # We've found one of the time elapsed values which are added at the end of layers - - # If total_time was not already found then noop - if (total_time == -1): - continue - - # Calculate percentage value this layer ends at - layer_end_percentage = int((self.getTimeValue(line) / total_time) * 100) - - # Figure out how many percent of the total time is spent in this layer - layer_percentage_delta = layer_end_percentage - previous_layer_end_percentage - - # If this layer represents less than 1 percent then we don't need to emit anything, continue to the next layer - if (layer_percentage_delta == 0): - continue - - # Grab the index of the current line and figure out how many lines represent one percent - step = lines.index(line) / layer_percentage_delta - - for percentage in range(1, layer_percentage_delta + 1): - # We add the percentage value here as while processing prior lines we will have inserted - # percentage lines before the current one. Failing to do this will upset the spacing - line_index = int((percentage * step) + percentage) - - # Due to integer truncation of the total time value in the gcode the percentage we - # calculate may slightly exceed 100, as that is not valid we cap the value here - output = min(percentage + previous_layer_end_percentage, 100) - - # Now insert the sanitized percentage into the GCODE - lines.insert(line_index, "M73 P{}".format(output)) - - previous_layer_end_percentage = layer_end_percentage - - # Join up the lines for this layer again and store them in the data array - data[layer_index] = "\n".join(lines) - return data diff --git a/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py index 8262061134..67534eb1eb 100644 --- a/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py +++ b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py @@ -3,92 +3,123 @@ # Date: July 31, 2019 # Modified: May 13, 2020 -# Description: This plugin displayes the remaining time on the LCD of the printer -# using the estimated print-time generated by Cura. - - - +# Description: This plugin displays progress on the LCD. It can output the estimated time remaining and the completion percentage. from ..Script import Script import re import datetime - -class DisplayProgressOnLCD(Script): +class DisplayPercentCompleteOnLCD(Script): def __init__(self): super().__init__() - def getSettingDataString(self): return """{ - "name":"Display Progress on LCD", - "key":"DisplayProgressOnLCD", + "name":"Display Percent Complete on LCD", + "key":"DisplayPercentCompleteOnLCD", "metadata": {}, "version": 2, "settings": { - "TurnOn": + "TimeRemaining": { "label": "Enable", - "description": "When enabled, It will write Time Left: HHMMSS on the display. This is updated every layer.", + "description": "When enabled, write Time Left: HHMMSS on the display using M117. This is updated every layer.", + "type": "bool", + "default_value": false + } + } + { + "Percentage": + { + "label": "Enable", + "description": "When enabled, set the completion bar percentage on the LCD using Marlin's M73 command.", "type": "bool", "default_value": false } } }""" + # Get the time value from a line as a float. + # Example line ;TIME_ELAPSED:1234.6789 or ;TIME:1337 + def getTimeValue(self, line): + list_split = re.split(":", line) # Split at ":" so we can get the numerical value + return float(list_split[1]) # Convert the numerical portion to a float + def execute(self, data): - if self.getSettingValueByKey("TurnOn"): - total_time = 0 - total_time_string = "" + output_time = self.getSettingValueByKey("TimeRemaining") + output_percentage = self.getSettingValueByKey("Percentage") + if (output_percentage or output_time) == True: + total_time = -1 + previous_layer_end_percentage = 0 for layer in data: layer_index = data.index(layer) lines = layer.split("\n") + for line in lines: - if line.startswith(";TIME:"): - # At this point, we have found a line in the GCODE with ";TIME:" - # which is the indication of total_time. Looks like: ";TIME:1337", where - # 1337 is the total print time in seconds. - line_index = lines.index(line) # We take a hold of that line - split_string = re.split(":", line) # Then we split it, so we can get the number - - string_with_numbers = "{}".format(split_string[1]) # Here we insert that number from the - # list into a string. - total_time = int(string_with_numbers) # Only to contert it to a int. - - m, s = divmod(total_time, 60) # Math to calculate - h, m = divmod(m, 60) # hours, minutes and seconds. - total_time_string = "{:d}h{:02d}m{:02d}s".format(h, m, s) # Now we put it into the string - lines[line_index] = "M117 Time Left {}".format(total_time_string) # And print that string instead of the original one - + if line.startswith(";TIME:") and total_time == -1: + # This line represents the total time required to print the gcode + total_time = self.getTimeValue(line) + line_index = lines.index(line) + if (output_time): + m, s = divmod(total_time, 60) # Math to calculate + h, m = divmod(m, 60) # hours, minutes and seconds. + total_time_string = "{:d}h{:02d}m{:02d}s".format(h, m, s) # Now we put it into the string + lines.insert(line_index, "M117 Time Left {}".format(total_time_string)) # And print that string instead of the original one + if (output_percentage): + # Emit 0 percent to sure Marlin knows we are overriding the completion percentage + lines.insert(line_index,"M73 P0") elif line.startswith(";TIME_ELAPSED:"): + # We've found one of the time elapsed values which are added at the end of layers - # As we didnt find the total time (";TIME:"), we have found a elapsed time mark - # This time represents the time the printer have printed. So with some math; - # totalTime - printTime = RemainingTime. - line_index = lines.index(line) # We get a hold of the line - list_split = re.split(":", line) # Again, we split at ":" so we can get the number - string_with_numbers = "{}".format(list_split[1]) # Then we put that number from the list, into a string + # If total_time was not already found then noop + if (total_time == -1): + continue - current_time = float(string_with_numbers) # This time we convert to a float, as the line looks something like: - # ;TIME_ELAPSED:1234.6789 - # which is total time in seconds + current_time = self.getTimeValue(line) + line_index = lines.index(line) + + if (output_time): + # Here we calculate remaining time and do some math to get the total time in seconds into the right format. (HH,MM,SS) + time_left = total_time - current_time + m1, s1 = divmod(time_left, 60) + h1, m1 = divmod(m1, 60) + # Here we create the string holding our time + current_time_string = "{:d}h{:2d}m{:2d}s".format(int(h1), int(m1), int(s1)) + # And now insert that into the GCODE + lines.insert(line_index, "M117 Time Left {}".format(current_time_string)) - time_left = total_time - current_time # Here we calculate remaining time - m1, s1 = divmod(time_left, 60) # And some math to get the total time in seconds into - h1, m1 = divmod(m1, 60) # the right format. (HH,MM,SS) - current_time_string = "{:d}h{:2d}m{:2d}s".format(int(h1), int(m1), int(s1)) # Here we create the string holding our time - lines[line_index] = "M117 Time Left {}".format(current_time_string) # And now insert that into the GCODE + if (output_percentage): + # Calculate percentage value this layer ends at + layer_end_percentage = int((current_time / total_time) * 100) + # Figure out how many percent of the total time is spent in this layer + layer_percentage_delta = layer_end_percentage - previous_layer_end_percentage + + # If this layer represents less than 1 percent then we don't need to emit anything, continue to the next layer + if (layer_percentage_delta != 0): + # Grab the index of the current line and figure out how many lines represent one percent + step = line_index / layer_percentage_delta - # Here we are OUT of the second for-loop - # Which means we have found and replaces all the occurences. - # Which also means we are ready to join the lines for that section of the GCODE file. - final_lines = "\n".join(lines) - data[layer_index] = final_lines + for percentage in range(1, layer_percentage_delta + 1): + # We add the percentage value here as while processing prior lines we will have inserted + # percentage lines before the current one. Failing to do this will upset the spacing + percentage_line_index = int((percentage * step) + percentage) + + # Due to integer truncation of the total time value in the gcode the percentage we + # calculate may slightly exceed 100, as that is not valid we cap the value here + output = min(percentage + previous_layer_end_percentage, 100) + + # Now insert the sanitized percentage into the GCODE + lines.insert(percentage_line_index, "M73 P{}".format(output)) + + previous_layer_end_percentage = layer_end_percentage + + # Join up the lines for this layer again and store them in the data array + data[layer_index] = "\n".join(lines) return data From d7c373b720fe3152caffb2cd71103d198f16e1c2 Mon Sep 17 00:00:00 2001 From: Alexander Gee Date: Wed, 13 May 2020 23:55:12 -0500 Subject: [PATCH 04/28] Extract method --- .../scripts/DisplayProgressOnLCD.py | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py index 67534eb1eb..5ca42e4c84 100644 --- a/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py +++ b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py @@ -48,6 +48,15 @@ class DisplayPercentCompleteOnLCD(Script): list_split = re.split(":", line) # Split at ":" so we can get the numerical value return float(list_split[1]) # Convert the numerical portion to a float + def outputTime(self, lines, line_index, time_left): + # Do some math to get the time left in seconds into the right format. (HH,MM,SS) + m, s = divmod(time_left, 60) + h, m = divmod(m, 60) + # Create the string + current_time_string = "{:d}h{:02d}m{:02d}s".format(int(h), int(m), int(s)) + # And now insert that into the GCODE + lines.insert(line_index, "M117 Time Left {}".format(current_time_string)) + def execute(self, data): output_time = self.getSettingValueByKey("TimeRemaining") output_percentage = self.getSettingValueByKey("Percentage") @@ -65,13 +74,10 @@ class DisplayPercentCompleteOnLCD(Script): line_index = lines.index(line) if (output_time): - m, s = divmod(total_time, 60) # Math to calculate - h, m = divmod(m, 60) # hours, minutes and seconds. - total_time_string = "{:d}h{:02d}m{:02d}s".format(h, m, s) # Now we put it into the string - lines.insert(line_index, "M117 Time Left {}".format(total_time_string)) # And print that string instead of the original one + self.outputTime(lines, line_index, total_time) if (output_percentage): # Emit 0 percent to sure Marlin knows we are overriding the completion percentage - lines.insert(line_index,"M73 P0") + lines.insert(line_index, "M73 P0") elif line.startswith(";TIME_ELAPSED:"): @@ -85,14 +91,8 @@ class DisplayPercentCompleteOnLCD(Script): line_index = lines.index(line) if (output_time): - # Here we calculate remaining time and do some math to get the total time in seconds into the right format. (HH,MM,SS) - time_left = total_time - current_time - m1, s1 = divmod(time_left, 60) - h1, m1 = divmod(m1, 60) - # Here we create the string holding our time - current_time_string = "{:d}h{:2d}m{:2d}s".format(int(h1), int(m1), int(s1)) - # And now insert that into the GCODE - lines.insert(line_index, "M117 Time Left {}".format(current_time_string)) + # Here we calculate remaining time + self.outputTime(lines, line_index, total_time - current_time) if (output_percentage): # Calculate percentage value this layer ends at From bd7248fe7320ad191043ea14c95d481df35fd214 Mon Sep 17 00:00:00 2001 From: Alexander Gee Date: Tue, 19 May 2020 18:48:52 -0500 Subject: [PATCH 05/28] Add line_set to avoid infinte loops --- .../scripts/DisplayProgressOnLCD.py | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py index 5ca42e4c84..01c0eb7d06 100644 --- a/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py +++ b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py @@ -10,31 +10,29 @@ from ..Script import Script import re import datetime -class DisplayPercentCompleteOnLCD(Script): +class DisplayProgressOnLCD(Script): def __init__(self): super().__init__() def getSettingDataString(self): return """{ - "name":"Display Percent Complete on LCD", - "key":"DisplayPercentCompleteOnLCD", + "name":"Display Progress On LCD", + "key":"DisplayProgressOnLCD", "metadata": {}, "version": 2, "settings": { "TimeRemaining": { - "label": "Enable", + "label": "Time Remaining", "description": "When enabled, write Time Left: HHMMSS on the display using M117. This is updated every layer.", "type": "bool", "default_value": false - } - } - { + }, "Percentage": { - "label": "Enable", + "label": "Percentage", "description": "When enabled, set the completion bar percentage on the LCD using Marlin's M73 command.", "type": "bool", "default_value": false @@ -60,6 +58,7 @@ class DisplayPercentCompleteOnLCD(Script): def execute(self, data): output_time = self.getSettingValueByKey("TimeRemaining") output_percentage = self.getSettingValueByKey("Percentage") + line_set = {} if (output_percentage or output_time) == True: total_time = -1 previous_layer_end_percentage = 0 @@ -82,6 +81,13 @@ class DisplayPercentCompleteOnLCD(Script): elif line.startswith(";TIME_ELAPSED:"): # We've found one of the time elapsed values which are added at the end of layers + + # If we have seen this line before then skip processing it. We can see lines multiple times because we are adding + # intermediate percentages before the line being processed. This can cause the current line to shift back and be + # encountered more than once + if (line in line_set): + continue + line_set[line] = True # If total_time was not already found then noop if (total_time == -1): From 93fdd9151b94bc35d3da497dc42d681aee717ccb Mon Sep 17 00:00:00 2001 From: Alexander Gee Date: Fri, 8 May 2020 19:22:40 -0500 Subject: [PATCH 06/28] Add PostProcessingPlugin script DisplayPercentCompleteOnLCD --- .../scripts/DisplayPercentCompleteOnLCD.py | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 plugins/PostProcessingPlugin/scripts/DisplayPercentCompleteOnLCD.py diff --git a/plugins/PostProcessingPlugin/scripts/DisplayPercentCompleteOnLCD.py b/plugins/PostProcessingPlugin/scripts/DisplayPercentCompleteOnLCD.py new file mode 100644 index 0000000000..41cb390f7b --- /dev/null +++ b/plugins/PostProcessingPlugin/scripts/DisplayPercentCompleteOnLCD.py @@ -0,0 +1,93 @@ +# Cura PostProcessingPlugin +# Author: Alexander Gee +# Date: May 3, 2020 +# Modified: May 3, 2020 + +# Description: This plugin will write the percent of time complete on the LCD using Marlin's M73 command. + + +from ..Script import Script + +import re + +class DisplayPercentCompleteOnLCD(Script): + + def __init__(self): + super().__init__() + + def getSettingDataString(self): + return """{ + "name":"Display Percent Complete on LCD", + "key":"DisplayPercentCompleteOnLCD", + "metadata": {}, + "version": 2, + "settings": + { + "TurnOn": + { + "label": "Enable", + "description": "When enabled, It will write the percent of time complete on the LCD using Marlin's M73 command.", + "type": "bool", + "default_value": false + } + } + }""" + + # Get the time value from a line as a float. + # Example line ;TIME_ELAPSED:1234.6789 or ;TIME:1337 + def getTimeValue(self, line): + list_split = re.split(":", line) # Split at ":" so we can get the numerical value + return float(list_split[1]) # Convert the numerical portion to a float + + def execute(self, data): + if self.getSettingValueByKey("TurnOn"): + total_time = -1 + previous_layer_end_percentage = 0 + for layer in data: + layer_index = data.index(layer) + lines = layer.split("\n") + + for line in lines: + if line.startswith(";TIME:") and total_time == -1: + # This line represents the total time required to print the gcode + total_time = self.getTimeValue(line) + # Emit 0 percent to sure Marlin knows we are overriding the completion percentage + lines.insert(lines.index(line),"M73 P0") + + elif line.startswith(";TIME_ELAPSED:"): + # We've found one of the time elapsed values which are added at the end of layers + + # If total_time was not already found then noop + if (total_time == -1): + continue + + # Calculate percentage value this layer ends at + layer_end_percentage = int((self.getTimeValue(line) / total_time) * 100) + + # Figure out how many percent of the total time is spent in this layer + layer_percentage_delta = layer_end_percentage - previous_layer_end_percentage + + # If this layer represents less than 1 percent then we don't need to emit anything, continue to the next layer + if (layer_percentage_delta == 0): + continue + + # Grab the index of the current line and figure out how many lines represent one percent + step = lines.index(line) / layer_percentage_delta + + for percentage in range(1, layer_percentage_delta + 1): + # We add the percentage value here as while processing prior lines we will have inserted + # percentage lines before the current one. Failing to do this will upset the spacing + line_index = int((percentage * step) + percentage) + + # Due to integer truncation of the total time value in the gcode the percentage we + # calculate may slightly exceed 100, as that is not valid we cap the value here + output = min(percentage + previous_layer_end_percentage, 100) + + # Now insert the sanitized percentage into the GCODE + lines.insert(line_index, "M73 P{}".format(output)) + + previous_layer_end_percentage = layer_end_percentage + + # Join up the lines for this layer again and store them in the data array + data[layer_index] = "\n".join(lines) + return data From 63b4c470953dc7f3c7e43ba7b462a2aa0f89b864 Mon Sep 17 00:00:00 2001 From: Alexander Gee Date: Wed, 13 May 2020 23:35:39 -0500 Subject: [PATCH 07/28] Rename to DisplayProgressOnLCD --- ...ayRemainingTimeOnLCD.py => DisplayProgressOnLCD.py} | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) rename plugins/PostProcessingPlugin/scripts/{DisplayRemainingTimeOnLCD.py => DisplayProgressOnLCD.py} (95%) diff --git a/plugins/PostProcessingPlugin/scripts/DisplayRemainingTimeOnLCD.py b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py similarity index 95% rename from plugins/PostProcessingPlugin/scripts/DisplayRemainingTimeOnLCD.py rename to plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py index 7d9af10925..8262061134 100644 --- a/plugins/PostProcessingPlugin/scripts/DisplayRemainingTimeOnLCD.py +++ b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py @@ -1,7 +1,7 @@ # Cura PostProcessingPlugin -# Author: Mathias Lyngklip Kjeldgaard +# Author: Mathias Lyngklip Kjeldgaard, Alexander Gee # Date: July 31, 2019 -# Modified: November 26, 2019 +# Modified: May 13, 2020 # Description: This plugin displayes the remaining time on the LCD of the printer # using the estimated print-time generated by Cura. @@ -15,7 +15,7 @@ import re import datetime -class DisplayRemainingTimeOnLCD(Script): +class DisplayProgressOnLCD(Script): def __init__(self): super().__init__() @@ -23,8 +23,8 @@ class DisplayRemainingTimeOnLCD(Script): def getSettingDataString(self): return """{ - "name":"Display Remaining Time on LCD", - "key":"DisplayRemainingTimeOnLCD", + "name":"Display Progress on LCD", + "key":"DisplayProgressOnLCD", "metadata": {}, "version": 2, "settings": From 1519b05cdbab84e6f197e16d3b08673d0381b600 Mon Sep 17 00:00:00 2001 From: Alexander Gee Date: Wed, 13 May 2020 23:36:49 -0500 Subject: [PATCH 08/28] Incorperate percentage and time remaining scripts --- .../scripts/DisplayPercentCompleteOnLCD.py | 93 ------------- .../scripts/DisplayProgressOnLCD.py | 131 +++++++++++------- 2 files changed, 81 insertions(+), 143 deletions(-) delete mode 100644 plugins/PostProcessingPlugin/scripts/DisplayPercentCompleteOnLCD.py diff --git a/plugins/PostProcessingPlugin/scripts/DisplayPercentCompleteOnLCD.py b/plugins/PostProcessingPlugin/scripts/DisplayPercentCompleteOnLCD.py deleted file mode 100644 index 41cb390f7b..0000000000 --- a/plugins/PostProcessingPlugin/scripts/DisplayPercentCompleteOnLCD.py +++ /dev/null @@ -1,93 +0,0 @@ -# Cura PostProcessingPlugin -# Author: Alexander Gee -# Date: May 3, 2020 -# Modified: May 3, 2020 - -# Description: This plugin will write the percent of time complete on the LCD using Marlin's M73 command. - - -from ..Script import Script - -import re - -class DisplayPercentCompleteOnLCD(Script): - - def __init__(self): - super().__init__() - - def getSettingDataString(self): - return """{ - "name":"Display Percent Complete on LCD", - "key":"DisplayPercentCompleteOnLCD", - "metadata": {}, - "version": 2, - "settings": - { - "TurnOn": - { - "label": "Enable", - "description": "When enabled, It will write the percent of time complete on the LCD using Marlin's M73 command.", - "type": "bool", - "default_value": false - } - } - }""" - - # Get the time value from a line as a float. - # Example line ;TIME_ELAPSED:1234.6789 or ;TIME:1337 - def getTimeValue(self, line): - list_split = re.split(":", line) # Split at ":" so we can get the numerical value - return float(list_split[1]) # Convert the numerical portion to a float - - def execute(self, data): - if self.getSettingValueByKey("TurnOn"): - total_time = -1 - previous_layer_end_percentage = 0 - for layer in data: - layer_index = data.index(layer) - lines = layer.split("\n") - - for line in lines: - if line.startswith(";TIME:") and total_time == -1: - # This line represents the total time required to print the gcode - total_time = self.getTimeValue(line) - # Emit 0 percent to sure Marlin knows we are overriding the completion percentage - lines.insert(lines.index(line),"M73 P0") - - elif line.startswith(";TIME_ELAPSED:"): - # We've found one of the time elapsed values which are added at the end of layers - - # If total_time was not already found then noop - if (total_time == -1): - continue - - # Calculate percentage value this layer ends at - layer_end_percentage = int((self.getTimeValue(line) / total_time) * 100) - - # Figure out how many percent of the total time is spent in this layer - layer_percentage_delta = layer_end_percentage - previous_layer_end_percentage - - # If this layer represents less than 1 percent then we don't need to emit anything, continue to the next layer - if (layer_percentage_delta == 0): - continue - - # Grab the index of the current line and figure out how many lines represent one percent - step = lines.index(line) / layer_percentage_delta - - for percentage in range(1, layer_percentage_delta + 1): - # We add the percentage value here as while processing prior lines we will have inserted - # percentage lines before the current one. Failing to do this will upset the spacing - line_index = int((percentage * step) + percentage) - - # Due to integer truncation of the total time value in the gcode the percentage we - # calculate may slightly exceed 100, as that is not valid we cap the value here - output = min(percentage + previous_layer_end_percentage, 100) - - # Now insert the sanitized percentage into the GCODE - lines.insert(line_index, "M73 P{}".format(output)) - - previous_layer_end_percentage = layer_end_percentage - - # Join up the lines for this layer again and store them in the data array - data[layer_index] = "\n".join(lines) - return data diff --git a/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py index 8262061134..67534eb1eb 100644 --- a/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py +++ b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py @@ -3,92 +3,123 @@ # Date: July 31, 2019 # Modified: May 13, 2020 -# Description: This plugin displayes the remaining time on the LCD of the printer -# using the estimated print-time generated by Cura. - - - +# Description: This plugin displays progress on the LCD. It can output the estimated time remaining and the completion percentage. from ..Script import Script import re import datetime - -class DisplayProgressOnLCD(Script): +class DisplayPercentCompleteOnLCD(Script): def __init__(self): super().__init__() - def getSettingDataString(self): return """{ - "name":"Display Progress on LCD", - "key":"DisplayProgressOnLCD", + "name":"Display Percent Complete on LCD", + "key":"DisplayPercentCompleteOnLCD", "metadata": {}, "version": 2, "settings": { - "TurnOn": + "TimeRemaining": { "label": "Enable", - "description": "When enabled, It will write Time Left: HHMMSS on the display. This is updated every layer.", + "description": "When enabled, write Time Left: HHMMSS on the display using M117. This is updated every layer.", + "type": "bool", + "default_value": false + } + } + { + "Percentage": + { + "label": "Enable", + "description": "When enabled, set the completion bar percentage on the LCD using Marlin's M73 command.", "type": "bool", "default_value": false } } }""" + # Get the time value from a line as a float. + # Example line ;TIME_ELAPSED:1234.6789 or ;TIME:1337 + def getTimeValue(self, line): + list_split = re.split(":", line) # Split at ":" so we can get the numerical value + return float(list_split[1]) # Convert the numerical portion to a float + def execute(self, data): - if self.getSettingValueByKey("TurnOn"): - total_time = 0 - total_time_string = "" + output_time = self.getSettingValueByKey("TimeRemaining") + output_percentage = self.getSettingValueByKey("Percentage") + if (output_percentage or output_time) == True: + total_time = -1 + previous_layer_end_percentage = 0 for layer in data: layer_index = data.index(layer) lines = layer.split("\n") + for line in lines: - if line.startswith(";TIME:"): - # At this point, we have found a line in the GCODE with ";TIME:" - # which is the indication of total_time. Looks like: ";TIME:1337", where - # 1337 is the total print time in seconds. - line_index = lines.index(line) # We take a hold of that line - split_string = re.split(":", line) # Then we split it, so we can get the number - - string_with_numbers = "{}".format(split_string[1]) # Here we insert that number from the - # list into a string. - total_time = int(string_with_numbers) # Only to contert it to a int. - - m, s = divmod(total_time, 60) # Math to calculate - h, m = divmod(m, 60) # hours, minutes and seconds. - total_time_string = "{:d}h{:02d}m{:02d}s".format(h, m, s) # Now we put it into the string - lines[line_index] = "M117 Time Left {}".format(total_time_string) # And print that string instead of the original one - + if line.startswith(";TIME:") and total_time == -1: + # This line represents the total time required to print the gcode + total_time = self.getTimeValue(line) + line_index = lines.index(line) + if (output_time): + m, s = divmod(total_time, 60) # Math to calculate + h, m = divmod(m, 60) # hours, minutes and seconds. + total_time_string = "{:d}h{:02d}m{:02d}s".format(h, m, s) # Now we put it into the string + lines.insert(line_index, "M117 Time Left {}".format(total_time_string)) # And print that string instead of the original one + if (output_percentage): + # Emit 0 percent to sure Marlin knows we are overriding the completion percentage + lines.insert(line_index,"M73 P0") elif line.startswith(";TIME_ELAPSED:"): + # We've found one of the time elapsed values which are added at the end of layers - # As we didnt find the total time (";TIME:"), we have found a elapsed time mark - # This time represents the time the printer have printed. So with some math; - # totalTime - printTime = RemainingTime. - line_index = lines.index(line) # We get a hold of the line - list_split = re.split(":", line) # Again, we split at ":" so we can get the number - string_with_numbers = "{}".format(list_split[1]) # Then we put that number from the list, into a string + # If total_time was not already found then noop + if (total_time == -1): + continue - current_time = float(string_with_numbers) # This time we convert to a float, as the line looks something like: - # ;TIME_ELAPSED:1234.6789 - # which is total time in seconds + current_time = self.getTimeValue(line) + line_index = lines.index(line) + + if (output_time): + # Here we calculate remaining time and do some math to get the total time in seconds into the right format. (HH,MM,SS) + time_left = total_time - current_time + m1, s1 = divmod(time_left, 60) + h1, m1 = divmod(m1, 60) + # Here we create the string holding our time + current_time_string = "{:d}h{:2d}m{:2d}s".format(int(h1), int(m1), int(s1)) + # And now insert that into the GCODE + lines.insert(line_index, "M117 Time Left {}".format(current_time_string)) - time_left = total_time - current_time # Here we calculate remaining time - m1, s1 = divmod(time_left, 60) # And some math to get the total time in seconds into - h1, m1 = divmod(m1, 60) # the right format. (HH,MM,SS) - current_time_string = "{:d}h{:2d}m{:2d}s".format(int(h1), int(m1), int(s1)) # Here we create the string holding our time - lines[line_index] = "M117 Time Left {}".format(current_time_string) # And now insert that into the GCODE + if (output_percentage): + # Calculate percentage value this layer ends at + layer_end_percentage = int((current_time / total_time) * 100) + # Figure out how many percent of the total time is spent in this layer + layer_percentage_delta = layer_end_percentage - previous_layer_end_percentage + + # If this layer represents less than 1 percent then we don't need to emit anything, continue to the next layer + if (layer_percentage_delta != 0): + # Grab the index of the current line and figure out how many lines represent one percent + step = line_index / layer_percentage_delta - # Here we are OUT of the second for-loop - # Which means we have found and replaces all the occurences. - # Which also means we are ready to join the lines for that section of the GCODE file. - final_lines = "\n".join(lines) - data[layer_index] = final_lines + for percentage in range(1, layer_percentage_delta + 1): + # We add the percentage value here as while processing prior lines we will have inserted + # percentage lines before the current one. Failing to do this will upset the spacing + percentage_line_index = int((percentage * step) + percentage) + + # Due to integer truncation of the total time value in the gcode the percentage we + # calculate may slightly exceed 100, as that is not valid we cap the value here + output = min(percentage + previous_layer_end_percentage, 100) + + # Now insert the sanitized percentage into the GCODE + lines.insert(percentage_line_index, "M73 P{}".format(output)) + + previous_layer_end_percentage = layer_end_percentage + + # Join up the lines for this layer again and store them in the data array + data[layer_index] = "\n".join(lines) return data From 17d6321eff083916e3edbc4dbe80f71f944798f4 Mon Sep 17 00:00:00 2001 From: Alexander Gee Date: Wed, 13 May 2020 23:55:12 -0500 Subject: [PATCH 09/28] Extract method --- .../scripts/DisplayProgressOnLCD.py | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py index 67534eb1eb..5ca42e4c84 100644 --- a/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py +++ b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py @@ -48,6 +48,15 @@ class DisplayPercentCompleteOnLCD(Script): list_split = re.split(":", line) # Split at ":" so we can get the numerical value return float(list_split[1]) # Convert the numerical portion to a float + def outputTime(self, lines, line_index, time_left): + # Do some math to get the time left in seconds into the right format. (HH,MM,SS) + m, s = divmod(time_left, 60) + h, m = divmod(m, 60) + # Create the string + current_time_string = "{:d}h{:02d}m{:02d}s".format(int(h), int(m), int(s)) + # And now insert that into the GCODE + lines.insert(line_index, "M117 Time Left {}".format(current_time_string)) + def execute(self, data): output_time = self.getSettingValueByKey("TimeRemaining") output_percentage = self.getSettingValueByKey("Percentage") @@ -65,13 +74,10 @@ class DisplayPercentCompleteOnLCD(Script): line_index = lines.index(line) if (output_time): - m, s = divmod(total_time, 60) # Math to calculate - h, m = divmod(m, 60) # hours, minutes and seconds. - total_time_string = "{:d}h{:02d}m{:02d}s".format(h, m, s) # Now we put it into the string - lines.insert(line_index, "M117 Time Left {}".format(total_time_string)) # And print that string instead of the original one + self.outputTime(lines, line_index, total_time) if (output_percentage): # Emit 0 percent to sure Marlin knows we are overriding the completion percentage - lines.insert(line_index,"M73 P0") + lines.insert(line_index, "M73 P0") elif line.startswith(";TIME_ELAPSED:"): @@ -85,14 +91,8 @@ class DisplayPercentCompleteOnLCD(Script): line_index = lines.index(line) if (output_time): - # Here we calculate remaining time and do some math to get the total time in seconds into the right format. (HH,MM,SS) - time_left = total_time - current_time - m1, s1 = divmod(time_left, 60) - h1, m1 = divmod(m1, 60) - # Here we create the string holding our time - current_time_string = "{:d}h{:2d}m{:2d}s".format(int(h1), int(m1), int(s1)) - # And now insert that into the GCODE - lines.insert(line_index, "M117 Time Left {}".format(current_time_string)) + # Here we calculate remaining time + self.outputTime(lines, line_index, total_time - current_time) if (output_percentage): # Calculate percentage value this layer ends at From 91199c8501228929424d04e6ad9b7f0c83da2047 Mon Sep 17 00:00:00 2001 From: Alexander Gee Date: Tue, 19 May 2020 18:48:52 -0500 Subject: [PATCH 10/28] Add line_set to avoid infinte loops --- .../scripts/DisplayProgressOnLCD.py | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py index 5ca42e4c84..01c0eb7d06 100644 --- a/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py +++ b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py @@ -10,31 +10,29 @@ from ..Script import Script import re import datetime -class DisplayPercentCompleteOnLCD(Script): +class DisplayProgressOnLCD(Script): def __init__(self): super().__init__() def getSettingDataString(self): return """{ - "name":"Display Percent Complete on LCD", - "key":"DisplayPercentCompleteOnLCD", + "name":"Display Progress On LCD", + "key":"DisplayProgressOnLCD", "metadata": {}, "version": 2, "settings": { "TimeRemaining": { - "label": "Enable", + "label": "Time Remaining", "description": "When enabled, write Time Left: HHMMSS on the display using M117. This is updated every layer.", "type": "bool", "default_value": false - } - } - { + }, "Percentage": { - "label": "Enable", + "label": "Percentage", "description": "When enabled, set the completion bar percentage on the LCD using Marlin's M73 command.", "type": "bool", "default_value": false @@ -60,6 +58,7 @@ class DisplayPercentCompleteOnLCD(Script): def execute(self, data): output_time = self.getSettingValueByKey("TimeRemaining") output_percentage = self.getSettingValueByKey("Percentage") + line_set = {} if (output_percentage or output_time) == True: total_time = -1 previous_layer_end_percentage = 0 @@ -82,6 +81,13 @@ class DisplayPercentCompleteOnLCD(Script): elif line.startswith(";TIME_ELAPSED:"): # We've found one of the time elapsed values which are added at the end of layers + + # If we have seen this line before then skip processing it. We can see lines multiple times because we are adding + # intermediate percentages before the line being processed. This can cause the current line to shift back and be + # encountered more than once + if (line in line_set): + continue + line_set[line] = True # If total_time was not already found then noop if (total_time == -1): From e807a086b4c1db930972ad6125f398b9703e4973 Mon Sep 17 00:00:00 2001 From: Alexander Gee Date: Sat, 23 May 2020 16:42:01 -0500 Subject: [PATCH 11/28] Refactor setting names for consistancy, migration script --- .../scripts/DisplayProgressOnLCD.py | 14 +++++++------- .../VersionUpgrade462to47/VersionUpgrade462to47.py | 11 +++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py index 01c0eb7d06..ac195b3b6c 100644 --- a/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py +++ b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py @@ -1,7 +1,7 @@ # Cura PostProcessingPlugin # Author: Mathias Lyngklip Kjeldgaard, Alexander Gee # Date: July 31, 2019 -# Modified: May 13, 2020 +# Modified: May 22, 2020 # Description: This plugin displays progress on the LCD. It can output the estimated time remaining and the completion percentage. @@ -17,20 +17,20 @@ class DisplayProgressOnLCD(Script): def getSettingDataString(self): return """{ - "name":"Display Progress On LCD", - "key":"DisplayProgressOnLCD", + "name": "Display Progress On LCD", + "key": "DisplayProgressOnLCD", "metadata": {}, "version": 2, "settings": { - "TimeRemaining": + "time_remaining": { "label": "Time Remaining", "description": "When enabled, write Time Left: HHMMSS on the display using M117. This is updated every layer.", "type": "bool", "default_value": false }, - "Percentage": + "percentage": { "label": "Percentage", "description": "When enabled, set the completion bar percentage on the LCD using Marlin's M73 command.", @@ -56,8 +56,8 @@ class DisplayProgressOnLCD(Script): lines.insert(line_index, "M117 Time Left {}".format(current_time_string)) def execute(self, data): - output_time = self.getSettingValueByKey("TimeRemaining") - output_percentage = self.getSettingValueByKey("Percentage") + output_time = self.getSettingValueByKey("time_remaining") + output_percentage = self.getSettingValueByKey("percentage") line_set = {} if (output_percentage or output_time) == True: total_time = -1 diff --git a/plugins/VersionUpgrade/VersionUpgrade462to47/VersionUpgrade462to47.py b/plugins/VersionUpgrade/VersionUpgrade462to47/VersionUpgrade462to47.py index 7b328e10e6..9f99eeec79 100644 --- a/plugins/VersionUpgrade/VersionUpgrade462to47/VersionUpgrade462to47.py +++ b/plugins/VersionUpgrade/VersionUpgrade462to47/VersionUpgrade462to47.py @@ -120,6 +120,17 @@ class VersionUpgrade462to47(VersionUpgrade): if "redo_layers" in script_parser["PauseAtHeight"]: script_parser["PauseAtHeight"]["redo_layer"] = str(int(script_parser["PauseAtHeight"]["redo_layers"]) > 0) del script_parser["PauseAtHeight"]["redo_layers"] # Has been renamed to without the S. + + # Migrate DisplayCompleteOnLCD to DisplayProgressOnLCD + if script_id == "DisplayPercentCompleteOnLCD": + script_settings = script_parser.items(script_id) + script_parser.remove_section(script_id) + + script_id = "DisplayProgressOnLCD" + script_parser.add_section(script_id) + if (script_settings["TurnOn"] == "true"): + script_parser.set(script_id, "time_remaining", "true") + script_io = io.StringIO() script_parser.write(script_io) script_str = script_io.getvalue() From 0a8f94f82efbc86ce8dadeade9751504759920d4 Mon Sep 17 00:00:00 2001 From: Michal Schulz Date: Tue, 7 Jul 2020 12:02:01 +0200 Subject: [PATCH 12/28] Correctly select the color mode from GUI - this fixes bug #8040 --- plugins/ImageReader/ImageReaderUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ImageReader/ImageReaderUI.py b/plugins/ImageReader/ImageReaderUI.py index f4732c2843..103cd6f7e8 100644 --- a/plugins/ImageReader/ImageReaderUI.py +++ b/plugins/ImageReader/ImageReaderUI.py @@ -172,7 +172,7 @@ class ImageReaderUI(QObject): @pyqtSlot(int) def onColorModelChanged(self, value): - self.use_transparency_model = (value == 0) + self.use_transparency_model = (value == 1) @pyqtSlot(int) def onTransmittanceChanged(self, value): From 816aaafc1972d43d93913b9976a1ca7735037914 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Tue, 7 Jul 2020 16:11:03 +0200 Subject: [PATCH 13/28] Revert changes for CURA-5479 It was decided that functionality present in existing plugins is sufficient. No need to replicate it in our own codebase and take on the burden of maintenance CURA-5479 --- cura/CuraApplication.py | 2 +- cura/UI/PrintInformation.py | 43 +++++-------------- .../VersionUpgrade462to47.py | 9 ---- resources/qml/Preferences/GeneralPage.qml | 31 +++++-------- resources/texts/change_log.txt | 2 +- tests/TestPrintInformation.py | 9 +--- 6 files changed, 24 insertions(+), 72 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 82797cd231..bae212917a 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -533,7 +533,7 @@ class CuraApplication(QtApplication): preferences.addPreference("cura/active_mode", "simple") preferences.addPreference("cura/categories_expanded", "") - preferences.addPreference("cura/job_name_template", "{machine_name_short}_{project_name}") + preferences.addPreference("cura/jobname_prefix", True) preferences.addPreference("cura/select_models_on_load", False) preferences.addPreference("view/center_on_select", False) preferences.addPreference("mesh/scale_to_fit", False) diff --git a/cura/UI/PrintInformation.py b/cura/UI/PrintInformation.py index 95aceb67e1..ae4aab0407 100644 --- a/cura/UI/PrintInformation.py +++ b/cura/UI/PrintInformation.py @@ -252,11 +252,11 @@ class PrintInformation(QObject): self.materialNamesChanged.emit() def _onPreferencesChanged(self, preference: str) -> None: - if preference == "cura/job_name_template": - self._updateJobName() - elif preference == "cura/material_settings": - for build_plate_number in range(self._multi_build_plate_model.maxBuildPlate + 1): - self._calculateInformation(build_plate_number) + if preference != "cura/material_settings": + return + + for build_plate_number in range(self._multi_build_plate_model.maxBuildPlate + 1): + self._calculateInformation(build_plate_number) def _onActiveBuildPlateChanged(self) -> None: new_active_build_plate = self._multi_build_plate_model.activeBuildPlate @@ -305,8 +305,12 @@ class PrintInformation(QObject): # Only update the job name when it's not user-specified. if not self._is_user_specified_job_name: - if not self._pre_sliced: - self._job_name = self.parseTemplate() + if self._application.getInstance().getPreferences().getValue("cura/jobname_prefix") and not self._pre_sliced: + # Don't add abbreviation if it already has the exact same abbreviation. + if base_name.startswith(self._abbr_machine + "_"): + self._job_name = base_name + else: + self._job_name = self._abbr_machine + "_" + base_name else: self._job_name = base_name @@ -436,28 +440,3 @@ class PrintInformation(QObject): """Listen to scene changes to check if we need to reset the print information""" self.setToZeroPrintInformation(self._active_build_plate) - - def parseTemplate(self) -> str: - """Generate a print job name from the job name template - - The template is a user preference: "cura/job_name_template" - """ - template = self._application.getInstance().getPreferences().getValue("cura/job_name_template") - output = template - - output = output.replace("{machine_name_short}", self._abbr_machine) - - if "{machine_name}" in template: - global_container_stack = self._application.getGlobalContainerStack() - active_machine_type_name = global_container_stack.definition.getName() \ - if global_container_stack \ - else "no_machine" - - active_machine_type_name = active_machine_type_name.replace(" ", "_") - output = output.replace("{machine_name}", active_machine_type_name) - - if "{project_name}" in template: - base_name = self._stripAccents(self._base_name) - output = output.replace("{project_name}", base_name) - - return output diff --git a/plugins/VersionUpgrade/VersionUpgrade462to47/VersionUpgrade462to47.py b/plugins/VersionUpgrade/VersionUpgrade462to47/VersionUpgrade462to47.py index ae7e421ab8..a167c9917e 100644 --- a/plugins/VersionUpgrade/VersionUpgrade462to47/VersionUpgrade462to47.py +++ b/plugins/VersionUpgrade/VersionUpgrade462to47/VersionUpgrade462to47.py @@ -4,8 +4,6 @@ import configparser from typing import Tuple, List, Dict, Set import io - -from UM.Util import parseBool from UM.VersionUpgrade import VersionUpgrade @@ -44,13 +42,6 @@ class VersionUpgrade462to47(VersionUpgrade): parser["general"]["visible_settings"] = ";".join( set(parser["general"]["visible_settings"].split(";")).difference(_removed_settings)) - if "cura" in parser and "jobname_prefix" in parser["cura"]: - if not parseBool(parser["cura"]["jobname_prefix"]): - parser["cura"]["job_name_template"] = "{project_name}" - del parser["cura"]["jobname_prefix"] - # else: When the jobname_prefix preference is True or not set, - # the default value for job_name_template ("{machine_name_short}_{project_name}") will be used - result = io.StringIO() parser.write(result) return [filename], [result.getvalue()] diff --git a/resources/qml/Preferences/GeneralPage.qml b/resources/qml/Preferences/GeneralPage.qml index 0d3f6ea586..62768556e4 100644 --- a/resources/qml/Preferences/GeneralPage.qml +++ b/resources/qml/Preferences/GeneralPage.qml @@ -85,8 +85,8 @@ UM.PreferencesPage scaleTinyCheckbox.checked = boolCheck(UM.Preferences.getValue("mesh/scale_tiny_meshes")) UM.Preferences.resetPreference("cura/select_models_on_load") selectModelsOnLoadCheckbox.checked = boolCheck(UM.Preferences.getValue("cura/select_models_on_load")) - UM.Preferences.resetPreference("cura/job_name_template") - jobnameTemplateTextField.text = UM.Preferences.getValue("cura/job_name_template") + UM.Preferences.resetPreference("cura/jobname_prefix") + prefixJobNameCheckbox.checked = boolCheck(UM.Preferences.getValue("cura/jobname_prefix")) UM.Preferences.resetPreference("view/show_overhang"); showOverhangCheckbox.checked = boolCheck(UM.Preferences.getValue("view/show_overhang")) UM.Preferences.resetPreference("view/show_xray_warning"); @@ -627,25 +627,14 @@ UM.PreferencesPage { width: childrenRect.width height: childrenRect.height - text: catalog.i18nc("@info:tooltip. Note variable names themselves (ie. machine_name_short, project_name) should not be translated", "Variables: machine_name_short, machine_name, project_name") + text: catalog.i18nc("@info:tooltip", "Should a prefix based on the printer name be added to the print job name automatically?") - Column + CheckBox { - spacing: 4 * screenScaleFactor - - Label - { - id: jobNameTemplateLabel - text: catalog.i18nc("@label","Print job template:") - } - - TextField - { - id: jobNameTemplateTextField - width: 250 * screenScaleFactor - text: UM.Preferences.getValue("cura/job_name_template") - onTextChanged: UM.Preferences.setValue("cura/job_name_template", text) - } + id: prefixJobNameCheckbox + text: catalog.i18nc("@option:check", "Add machine prefix to job name") + checked: boolCheck(UM.Preferences.getValue("cura/jobname_prefix")) + onCheckedChanged: UM.Preferences.setValue("cura/jobname_prefix", checked) } } @@ -681,7 +670,7 @@ UM.PreferencesPage ComboBox { id: choiceOnOpenProjectDropDownButton - width: 250 * screenScaleFactor + width: 200 * screenScaleFactor model: ListModel { @@ -747,7 +736,7 @@ UM.PreferencesPage ComboBox { id: choiceOnProfileOverrideDropDownButton - width: 250 * screenScaleFactor + width: 200 * screenScaleFactor model: ListModel { diff --git a/resources/texts/change_log.txt b/resources/texts/change_log.txt index 7621f6f713..8ce125d932 100644 --- a/resources/texts/change_log.txt +++ b/resources/texts/change_log.txt @@ -140,7 +140,7 @@ A new performance enhancement that limits re-rendering of the application interf Previous versions used different ways of handling HTTP requests. This version uses a unified method, for better performance. * Job names less sensitive to being touched. -A contribution from fieldOfview has fixed an issue where the job name in the bottom-left of the scene is no longer made static by clicking on it. If you load a model and change to another printer, the prefix is now correctly updated. +A contribution from fieldOfview has fixed an issue where the jobname in the bottom-left of the scene is no longer made static by clicking on it. If you load a model and change to another printer, the prefix is now correctly updated. * Property checks on instance containers. A new speed optimization for reading setting values from profiles. diff --git a/tests/TestPrintInformation.py b/tests/TestPrintInformation.py index 577827f326..5133dfcafb 100644 --- a/tests/TestPrintInformation.py +++ b/tests/TestPrintInformation.py @@ -8,13 +8,6 @@ from unittest.mock import MagicMock, patch from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType -def preferencesGetValue(key: str): - if key == "cura/job_name_template": - return "{machine_name_short}_{project_name}" - - return '{"omgzomg": {"spool_weight": 10, "spool_cost": 9}}' - - def getPrintInformation(printer_name) -> PrintInformation: mock_application = MagicMock(name = "mock_application") @@ -26,7 +19,7 @@ def getPrintInformation(printer_name) -> PrintInformation: mocked_extruder_stack.material = mocked_material mock_application.getInstance = MagicMock(return_value = mock_application) - mocked_preferences.getValue = MagicMock(side_effect = preferencesGetValue) + mocked_preferences.getValue = MagicMock(return_value = '{"omgzomg": {"spool_weight": 10, "spool_cost": 9}}') global_container_stack = MagicMock() global_container_stack.definition.getName = MagicMock(return_value = printer_name) From 0a97511d3a8320e5d5d9b62617d646af667bae78 Mon Sep 17 00:00:00 2001 From: Alexander Gee Date: Wed, 8 Jul 2020 00:30:19 -0500 Subject: [PATCH 14/28] Apply suggestions from code review Co-authored-by: Konstantinos Karmas --- .../scripts/DisplayProgressOnLCD.py | 19 +++++++++---------- .../VersionUpgrade462to47.py | 8 ++++---- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py index ac195b3b6c..a445fb3a6e 100644 --- a/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py +++ b/plugins/PostProcessingPlugin/scripts/DisplayProgressOnLCD.py @@ -59,7 +59,7 @@ class DisplayProgressOnLCD(Script): output_time = self.getSettingValueByKey("time_remaining") output_percentage = self.getSettingValueByKey("percentage") line_set = {} - if (output_percentage or output_time) == True: + if output_percentage or output_time: total_time = -1 previous_layer_end_percentage = 0 for layer in data: @@ -72,35 +72,34 @@ class DisplayProgressOnLCD(Script): total_time = self.getTimeValue(line) line_index = lines.index(line) - if (output_time): + if output_time: self.outputTime(lines, line_index, total_time) - if (output_percentage): + if output_percentage: # Emit 0 percent to sure Marlin knows we are overriding the completion percentage lines.insert(line_index, "M73 P0") - elif line.startswith(";TIME_ELAPSED:"): # We've found one of the time elapsed values which are added at the end of layers # If we have seen this line before then skip processing it. We can see lines multiple times because we are adding # intermediate percentages before the line being processed. This can cause the current line to shift back and be # encountered more than once - if (line in line_set): + if line in line_set: continue line_set[line] = True # If total_time was not already found then noop - if (total_time == -1): + if total_time == -1: continue current_time = self.getTimeValue(line) line_index = lines.index(line) - if (output_time): + if output_time: # Here we calculate remaining time self.outputTime(lines, line_index, total_time - current_time) - if (output_percentage): + if output_percentage: # Calculate percentage value this layer ends at layer_end_percentage = int((current_time / total_time) * 100) @@ -108,7 +107,7 @@ class DisplayProgressOnLCD(Script): layer_percentage_delta = layer_end_percentage - previous_layer_end_percentage # If this layer represents less than 1 percent then we don't need to emit anything, continue to the next layer - if (layer_percentage_delta != 0): + if layer_percentage_delta != 0: # Grab the index of the current line and figure out how many lines represent one percent step = line_index / layer_percentage_delta @@ -127,5 +126,5 @@ class DisplayProgressOnLCD(Script): previous_layer_end_percentage = layer_end_percentage # Join up the lines for this layer again and store them in the data array - data[layer_index] = "\n".join(lines) + data[layer_index] = "\n".join(lines) return data diff --git a/plugins/VersionUpgrade/VersionUpgrade462to47/VersionUpgrade462to47.py b/plugins/VersionUpgrade/VersionUpgrade462to47/VersionUpgrade462to47.py index 3461ead8d2..7e9294c190 100644 --- a/plugins/VersionUpgrade/VersionUpgrade462to47/VersionUpgrade462to47.py +++ b/plugins/VersionUpgrade/VersionUpgrade462to47/VersionUpgrade462to47.py @@ -122,14 +122,14 @@ class VersionUpgrade462to47(VersionUpgrade): del script_parser["PauseAtHeight"]["redo_layers"] # Has been renamed to without the S. # Migrate DisplayCompleteOnLCD to DisplayProgressOnLCD - if script_id == "DisplayPercentCompleteOnLCD": - was_enabled = script_parser[script_id]["TurnOn"] == "true" if "TurnOn" in script_parser[script_id] else False + if script_id == "DisplayRemainingTimeOnLCD": + was_enabled = parseBool(script_parser[script_id]["TurnOn"]) if "TurnOn" in script_parser[script_id] else False script_parser.remove_section(script_id) script_id = "DisplayProgressOnLCD" script_parser.add_section(script_id) - if (was_enabled): - script_parser.set(script_id, "time_remaining", "true") + if was_enabled: + script_parser.set(script_id, "time_remaining", "True") script_io = io.StringIO() script_parser.write(script_io) From 91690524c0e11f7accde6fd802c9aab1348ad0f0 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 8 Jul 2020 10:39:33 +0200 Subject: [PATCH 15/28] Ensure that the 3mf reader doesn't make groups of one --- plugins/3MFReader/ThreeMFReader.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py index 546c6fc27b..2e035c7a59 100755 --- a/plugins/3MFReader/ThreeMFReader.py +++ b/plugins/3MFReader/ThreeMFReader.py @@ -169,8 +169,16 @@ class ThreeMFReader(MeshReader): setting_container.setProperty(key, "value", setting_value) if len(um_node.getChildren()) > 0 and um_node.getMeshData() is None: - group_decorator = GroupDecorator() - um_node.addDecorator(group_decorator) + if len(um_node.getAllChildren()) == 1: + # We don't want groups of one, so move the node up one "level" + child_node = um_node.getChildren()[0] + parent_transformation = um_node.getLocalTransformation() + child_transformation = child_node.getLocalTransformation() + child_node.setTransformation(parent_transformation.multiply(child_transformation)) + um_node = um_node.getChildren()[0] + else: + group_decorator = GroupDecorator() + um_node.addDecorator(group_decorator) um_node.setSelectable(True) if um_node.getMeshData(): # Assuming that all nodes with mesh data are printable objects @@ -192,8 +200,8 @@ class ThreeMFReader(MeshReader): um_node = self._convertSavitarNodeToUMNode(node, file_name) if um_node is None: continue - # compensate for original center position, if object(s) is/are not around its zero position + # compensate for original center position, if object(s) is/are not around its zero position transform_matrix = Matrix() mesh_data = um_node.getMeshData() if mesh_data is not None: From 38256f7a98e4c3f5c7fd561c51970c758180aa6c Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 8 Jul 2020 11:05:46 +0200 Subject: [PATCH 16/28] Add cast so that mypy doesn't choke --- plugins/3MFReader/ThreeMFReader.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py index 2e035c7a59..2c29728d66 100755 --- a/plugins/3MFReader/ThreeMFReader.py +++ b/plugins/3MFReader/ThreeMFReader.py @@ -3,7 +3,7 @@ import os.path import zipfile -from typing import List, Optional, Union, TYPE_CHECKING +from typing import List, Optional, Union, TYPE_CHECKING, cast import Savitar import numpy @@ -175,7 +175,7 @@ class ThreeMFReader(MeshReader): parent_transformation = um_node.getLocalTransformation() child_transformation = child_node.getLocalTransformation() child_node.setTransformation(parent_transformation.multiply(child_transformation)) - um_node = um_node.getChildren()[0] + um_node = cast(CuraSceneNode, um_node.getChildren()[0]) else: group_decorator = GroupDecorator() um_node.addDecorator(group_decorator) From e000efe49304331c5af7870f0c72b98f8da30e41 Mon Sep 17 00:00:00 2001 From: Kostas Karmas Date: Wed, 8 Jul 2020 17:37:00 +0200 Subject: [PATCH 17/28] Fix missing import Related to https://github.com/Ultimaker/Cura/pull/7726 --- .../VersionUpgrade462to47/VersionUpgrade462to47.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/VersionUpgrade/VersionUpgrade462to47/VersionUpgrade462to47.py b/plugins/VersionUpgrade/VersionUpgrade462to47/VersionUpgrade462to47.py index 396b17b4be..54573359cf 100644 --- a/plugins/VersionUpgrade/VersionUpgrade462to47/VersionUpgrade462to47.py +++ b/plugins/VersionUpgrade/VersionUpgrade462to47/VersionUpgrade462to47.py @@ -4,6 +4,8 @@ import configparser from typing import Tuple, List, Dict, Set import io + +from UM.Util import parseBool from UM.VersionUpgrade import VersionUpgrade From b1cd5960b82f3c08c95881ae462ae3239efa35df Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 10 Jul 2020 13:23:30 +0200 Subject: [PATCH 18/28] Load a number of dialogs on demand instead of always Knocks off 0.4 sec of booting. --- resources/qml/Cura.qml | 1 + resources/qml/WelcomePages/WizardDialog.qml | 1 + resources/qml/WelcomePages/WizardPanel.qml | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index c9a16e579a..c3d9dfbf96 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -866,6 +866,7 @@ UM.MainWindow title: catalog.i18nc("@title:window", "What's New") model: CuraApplication.getWhatsNewPagesModel() progressBarVisible: false + visible: false } Connections diff --git a/resources/qml/WelcomePages/WizardDialog.qml b/resources/qml/WelcomePages/WizardDialog.qml index c14974cd03..3bee9fcb5c 100644 --- a/resources/qml/WelcomePages/WizardDialog.qml +++ b/resources/qml/WelcomePages/WizardDialog.qml @@ -40,6 +40,7 @@ Window id: wizardPanel anchors.fill: parent model: dialog.model + visible: dialog.visible } // Close this dialog when there's no more page to show diff --git a/resources/qml/WelcomePages/WizardPanel.qml b/resources/qml/WelcomePages/WizardPanel.qml index 418f4848fb..db4b66d18b 100644 --- a/resources/qml/WelcomePages/WizardPanel.qml +++ b/resources/qml/WelcomePages/WizardPanel.qml @@ -71,7 +71,7 @@ Item right: parent.right } source: base.pageUrl - enabled: base.visible + active: base.visible } } } From b7296dd700e39bcaa92aab97ab6ff2c94d3f41c2 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 10 Jul 2020 13:48:47 +0200 Subject: [PATCH 19/28] Don't update material menu when it's not visible Knocks off about a second of loading --- resources/qml/Menus/SettingsMenu.qml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/resources/qml/Menus/SettingsMenu.qml b/resources/qml/Menus/SettingsMenu.qml index a7c8d7479f..939ade5847 100644 --- a/resources/qml/Menus/SettingsMenu.qml +++ b/resources/qml/Menus/SettingsMenu.qml @@ -2,7 +2,7 @@ //Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.2 -import QtQuick.Controls 1.1 +import QtQuick.Controls 1.4 import UM 1.2 as UM import Cura 1.0 as Cura @@ -24,7 +24,15 @@ Menu title: modelData.name property var extruder: (base.activeMachine === null) ? null : activeMachine.extruderList[model.index] NozzleMenu { title: Cura.MachineManager.activeDefinitionVariantsName; visible: Cura.MachineManager.activeMachine.hasVariants; extruderIndex: index } - MaterialMenu { title: catalog.i18nc("@title:menu", "&Material"); visible: Cura.MachineManager.activeMachine.hasMaterials; extruderIndex: index } + MaterialMenu + { + title: catalog.i18nc("@title:menu", "&Material") + visible: Cura.MachineManager.activeMachine.hasMaterials + extruderIndex: index + updateModels: false + onAboutToShow: updateModels = true + onAboutToHide: updateModels = false + } MenuSeparator { From c5d5cd2c594b1383787b69da10fc0cb4596a3d08 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 10 Jul 2020 13:54:16 +0200 Subject: [PATCH 20/28] Precompute delegate height for settingview Speed up the rendering of settingitems a bit --- resources/qml/Settings/SettingView.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 5dfba3e464..4c31988eb0 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -246,13 +246,14 @@ Item } property int indexWithFocus: -1 + property double delegateHeight: UM.Theme.getSize("section").height + 2 * UM.Theme.getSize("default_lining").height property string activeMachineId: Cura.MachineManager.activeMachine !== null ? Cura.MachineManager.activeMachine.id : "" delegate: Loader { id: delegate width: scrollView.width - height: provider.properties.enabled === "True" ? UM.Theme.getSize("section").height + 2 * UM.Theme.getSize("default_lining").height : 0 + height: provider.properties.enabled === "True" ? contents.delegateHeight: 0 Behavior on height { NumberAnimation { duration: 100 } } opacity: provider.properties.enabled === "True" ? 1 : 0 Behavior on opacity { NumberAnimation { duration: 100 } } From ce3ac604f2352cb233e650815670b89fa29b4c7c Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 10 Jul 2020 14:05:39 +0200 Subject: [PATCH 21/28] Remove anchient check from the code We removed global tabs like 4 years ago, so no need to have the check. Speeds up the setting loading a bit more again --- resources/qml/Settings/SettingView.qml | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 4c31988eb0..610e065554 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -253,19 +253,11 @@ Item id: delegate width: scrollView.width - height: provider.properties.enabled === "True" ? contents.delegateHeight: 0 + height: enabled ? contents.delegateHeight: 0 Behavior on height { NumberAnimation { duration: 100 } } - opacity: provider.properties.enabled === "True" ? 1 : 0 + opacity: enabled ? 1 : 0 Behavior on opacity { NumberAnimation { duration: 100 } } - enabled: - { - if (!Cura.ExtruderManager.activeExtruderStackId && machineExtruderCount.properties.value > 1) - { - // disable all controls on the global tab, except categories - return model.type === "category" - } - return provider.properties.enabled === "True" - } + enabled: provider.properties.enabled === "True" property var definition: model property var settingDefinitionsModel: definitionsModel From d1afc6390258510450e6f061757025f62e257dcb Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 10 Jul 2020 14:28:58 +0200 Subject: [PATCH 22/28] Make all settingitems async We're quite a few qt versions ahead now. The issue seems to have been resolved in the meantime! --- resources/qml/Settings/SettingView.qml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 610e065554..108cf1a1f6 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -265,10 +265,7 @@ Item property var globalPropertyProvider: inheritStackProvider property bool externalResetHandler: false - //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989 - //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes, - //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely. - asynchronous: model.type !== "enum" && model.type !== "extruder" && model.type !== "optional_extruder" + asynchronous: true active: model.type !== undefined source: From e633b6408e19e3f6f8c30ec3c22f506779d86ae9 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 10 Jul 2020 14:34:02 +0200 Subject: [PATCH 23/28] Use pre-calculated control height It's way faster to not re-compute every single time --- resources/qml/Settings/SettingItem.qml | 2 +- resources/themes/cura-light/theme.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index 4f232cd7ee..f0c748d190 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -156,7 +156,7 @@ Item { id: settingControls - height: Math.round(parent.height / 2) + height: UM.Theme.getSize("section_control").height spacing: Math.round(UM.Theme.getSize("thick_margin").height / 2) anchors diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 10cb353c60..784f62965c 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -502,6 +502,7 @@ "extruder_icon": [2.33, 2.33], "section": [0.0, 2], + "section_control": [0, 1], "section_icon": [1.6, 1.6], "section_icon_column": [2.8, 0.0], "rating_star": [1.0, 1.0], From 8b7b8b01183a823a21ee26e84832cc7161d807bf Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 10 Jul 2020 14:50:44 +0200 Subject: [PATCH 24/28] Simplify the SettingCategory --- resources/qml/Settings/SettingCategory.qml | 70 ++++++---------------- resources/themes/cura-dark/theme.json | 4 -- resources/themes/cura-light/theme.json | 4 -- 3 files changed, 18 insertions(+), 60 deletions(-) diff --git a/resources/qml/Settings/SettingCategory.qml b/resources/qml/Settings/SettingCategory.qml index fd4a181a56..e3e12d7753 100644 --- a/resources/qml/Settings/SettingCategory.qml +++ b/resources/qml/Settings/SettingCategory.qml @@ -22,22 +22,10 @@ Button height: UM.Theme.getSize("section").height color: { - if (base.color) - { - return base.color - } - else if (!base.enabled) + if (!base.enabled) { return UM.Theme.getColor("setting_category_disabled") } - else if (base.hovered && base.expanded) - { - return UM.Theme.getColor("setting_category_active_hover") - } - else if (base.pressed || base.expanded) - { - return UM.Theme.getColor("setting_category_active") - } else if (base.hovered) { return UM.Theme.getColor("setting_category_hover") @@ -57,6 +45,21 @@ Button property var focusItem: base property bool expanded: definition.expanded + + property color text_color: + { + if (!base.enabled) + { + return UM.Theme.getColor("setting_category_disabled_text") + } else if (base.hovered || base.pressed || base.activeFocus) + { + return UM.Theme.getColor("setting_category_active_text") + } + + return UM.Theme.getColor("setting_category_text") + + } + contentItem: Item { anchors.fill: parent @@ -75,25 +78,7 @@ Button textFormat: Text.PlainText renderType: Text.NativeRendering font: UM.Theme.getFont("medium_bold") - color: - { - if (!base.enabled) - { - return UM.Theme.getColor("setting_category_disabled_text") - } else if ((base.hovered || base.activeFocus) && base.expanded) - { - return UM.Theme.getColor("setting_category_active_hover_text") - } else if (base.pressed || base.expanded) - { - return UM.Theme.getColor("setting_category_active_text") - } else if (base.hovered || base.activeFocus) - { - return UM.Theme.getColor("setting_category_hover_text") - } else - { - return UM.Theme.getColor("setting_category_text") - } - } + color: base.text_color fontSizeMode: Text.HorizontalFit minimumPointSize: 8 } @@ -118,26 +103,7 @@ Button anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("thin_margin").width - color: - { - if (!base.enabled) - { - return UM.Theme.getColor("setting_category_disabled_text") - } - else if((base.hovered || base.activeFocus) && base.expanded) - { - return UM.Theme.getColor("setting_category_active_hover_text") - } - else if(base.pressed || base.expanded) - { - return UM.Theme.getColor("setting_category_active_text") - } - else if(base.hovered || base.activeFocus) - { - return UM.Theme.getColor("setting_category_hover_text") - } - return UM.Theme.getColor("setting_category_text") - } + color: base.text_color source: UM.Theme.getIcon(definition.icon) width: UM.Theme.getSize("section_icon").width height: UM.Theme.getSize("section_icon").height diff --git a/resources/themes/cura-dark/theme.json b/resources/themes/cura-dark/theme.json index 69bd14765a..311aefcee0 100644 --- a/resources/themes/cura-dark/theme.json +++ b/resources/themes/cura-dark/theme.json @@ -99,13 +99,9 @@ "setting_category": [75, 80, 83, 255], "setting_category_disabled": [75, 80, 83, 255], "setting_category_hover": [75, 80, 83, 255], - "setting_category_active": [75, 80, 83, 255], - "setting_category_active_hover": [75, 80, 83, 255], "setting_category_text": [255, 255, 255, 152], "setting_category_disabled_text": [255, 255, 255, 101], - "setting_category_hover_text": [255, 255, 255, 204], "setting_category_active_text": [255, 255, 255, 204], - "setting_category_active_hover_text": [255, 255, 255, 204], "setting_category_border": [39, 44, 48, 0], "setting_category_disabled_border": [39, 44, 48, 0], "setting_category_hover_border": [12, 169, 227, 255], diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 784f62965c..a72c4eb5cd 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -274,13 +274,9 @@ "setting_category": [240, 240, 240, 255], "setting_category_disabled": [255, 255, 255, 255], "setting_category_hover": [232, 242, 252, 255], - "setting_category_active": [240, 240, 240, 255], - "setting_category_active_hover": [232, 242, 252, 255], "setting_category_text": [35, 35, 35, 255], "setting_category_disabled_text": [24, 41, 77, 101], - "setting_category_hover_text": [35, 35, 35, 255], "setting_category_active_text": [35, 35, 35, 255], - "setting_category_active_hover_text": [35, 35, 35, 255], "setting_category_border": [240, 240, 240, 255], "setting_category_disabled_border": [240, 240, 240, 255], "setting_category_hover_border": [50, 130, 255, 255], From 6d120c43b6d93422970ebd2e675164fdf6202338 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 10 Jul 2020 15:57:00 +0200 Subject: [PATCH 25/28] Remove unneeded null check The check takes ~1.5 ms. It's easily called a few hunderd times --- resources/qml/Settings/SettingView.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 108cf1a1f6..8a390bbaef 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -345,7 +345,7 @@ Item id: provider containerStackId: contents.activeMachineId - key: model.key ? model.key : "" + key: model.key watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder", "resolve" ] storeIndex: 0 removeUnusedValue: model.resolve === undefined From e010d4f945c62967cf5ebee9eedd64b74970b6e5 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 10 Jul 2020 16:44:55 +0200 Subject: [PATCH 26/28] Only enable clipping for list text fields Because clipping is expensive! --- resources/qml/Settings/SettingTextField.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Settings/SettingTextField.qml b/resources/qml/Settings/SettingTextField.qml index c0c7772104..d57bbaad8a 100644 --- a/resources/qml/Settings/SettingTextField.qml +++ b/resources/qml/Settings/SettingTextField.qml @@ -153,7 +153,7 @@ SettingItem selectByMouse: true maximumLength: (definition.type == "str" || definition.type == "[int]") ? -1 : 10 - clip: true; //Hide any text that exceeds the width of the text box. + clip: definition.type == "[int]" // Only clip for the list validator: RegExpValidator { regExp: (definition.type == "[int]") ? /^\[?(\s*-?[0-9]{0,9}\s*,)*(\s*-?[0-9]{0,9})\s*\]?$/ : (definition.type == "int") ? /^-?[0-9]{0,10}$/ : (definition.type == "float") ? /^-?[0-9]{0,9}[.,]?[0-9]{0,3}$/ : /^.*$/ } // definition.type property from parent loader used to disallow fractional number entry From 4372099e1d401a33f1b2adee8801386dbfb2e6e2 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 13 Jul 2020 11:45:16 +0200 Subject: [PATCH 27/28] Don't crash if material preferences are corrupt This time we don't need to catch permission errors and such since we're reading it from a string that was stored in memory (read when the preferences file was read). However we do need to catch JSON Decoding Errors since the JSON syntax might be broken by the user modifying these files or because the file wasn't saved properly before. Fixes Sentry issue CURA-112. --- cura/UI/PrintInformation.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cura/UI/PrintInformation.py b/cura/UI/PrintInformation.py index ae4aab0407..22710165b3 100644 --- a/cura/UI/PrintInformation.py +++ b/cura/UI/PrintInformation.py @@ -202,7 +202,11 @@ class PrintInformation(QObject): self._material_costs[build_plate_number] = [] self._material_names[build_plate_number] = [] - material_preference_values = json.loads(self._application.getInstance().getPreferences().getValue("cura/material_settings")) + try: + material_preference_values = json.loads(self._application.getInstance().getPreferences().getValue("cura/material_settings")) + except json.JSONDecodeError: + Logger.warning("Material preference values are corrupt. Will revert to defaults!") + material_preference_values = {} for index, extruder_stack in enumerate(global_stack.extruderList): if index >= len(self._material_amounts): From c38ee8a365732ade527e7a89883b53974ff4f70e Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 13 Jul 2020 13:47:51 +0200 Subject: [PATCH 28/28] Clear focus when changing tools This is a fix for a bug on MacOS where the delete key wasn't working. A text field from the tools was in focus, which caught the key event, preventing objects from being deleted. Fixes #7754 and CURA-7585. --- resources/qml/Toolbar.qml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/resources/qml/Toolbar.qml b/resources/qml/Toolbar.qml index 0bf09b4d18..89d64b06ad 100644 --- a/resources/qml/Toolbar.qml +++ b/resources/qml/Toolbar.qml @@ -78,6 +78,10 @@ Item { base.activeY = y; } + //Clear focus when tools change. This prevents the tool grabbing focus when activated. + //Grabbing focus prevents items from being deleted. + //Apparently this was only a problem on MacOS. + forceActiveFocus(); } //Workaround since using ToolButton's onClicked would break the binding of the checked property, instead