Merge branch 'master' into CURA-6711_support_structure_dropdown

This commit is contained in:
Nino van Hooff 2020-07-15 11:57:34 +02:00
commit bc51db321f
22 changed files with 238 additions and 252 deletions

View File

@ -533,7 +533,7 @@ class CuraApplication(QtApplication):
preferences.addPreference("cura/active_mode", "simple") preferences.addPreference("cura/active_mode", "simple")
preferences.addPreference("cura/categories_expanded", "") 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("cura/select_models_on_load", False)
preferences.addPreference("view/center_on_select", False) preferences.addPreference("view/center_on_select", False)
preferences.addPreference("mesh/scale_to_fit", False) preferences.addPreference("mesh/scale_to_fit", False)

View File

@ -202,7 +202,11 @@ class PrintInformation(QObject):
self._material_costs[build_plate_number] = [] self._material_costs[build_plate_number] = []
self._material_names[build_plate_number] = [] self._material_names[build_plate_number] = []
try:
material_preference_values = json.loads(self._application.getInstance().getPreferences().getValue("cura/material_settings")) 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): for index, extruder_stack in enumerate(global_stack.extruderList):
if index >= len(self._material_amounts): if index >= len(self._material_amounts):
@ -252,9 +256,9 @@ class PrintInformation(QObject):
self.materialNamesChanged.emit() self.materialNamesChanged.emit()
def _onPreferencesChanged(self, preference: str) -> None: def _onPreferencesChanged(self, preference: str) -> None:
if preference == "cura/job_name_template": if preference != "cura/material_settings":
self._updateJobName() return
elif preference == "cura/material_settings":
for build_plate_number in range(self._multi_build_plate_model.maxBuildPlate + 1): for build_plate_number in range(self._multi_build_plate_model.maxBuildPlate + 1):
self._calculateInformation(build_plate_number) self._calculateInformation(build_plate_number)
@ -305,8 +309,12 @@ class PrintInformation(QObject):
# Only update the job name when it's not user-specified. # Only update the job name when it's not user-specified.
if not self._is_user_specified_job_name: if not self._is_user_specified_job_name:
if not self._pre_sliced: if self._application.getInstance().getPreferences().getValue("cura/jobname_prefix") and not self._pre_sliced:
self._job_name = self.parseTemplate() # 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: else:
self._job_name = base_name self._job_name = base_name
@ -436,28 +444,3 @@ class PrintInformation(QObject):
"""Listen to scene changes to check if we need to reset the print information""" """Listen to scene changes to check if we need to reset the print information"""
self.setToZeroPrintInformation(self._active_build_plate) 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

View File

@ -3,7 +3,7 @@
import os.path import os.path
import zipfile import zipfile
from typing import List, Optional, Union, TYPE_CHECKING from typing import List, Optional, Union, TYPE_CHECKING, cast
import Savitar import Savitar
import numpy import numpy
@ -169,6 +169,14 @@ class ThreeMFReader(MeshReader):
setting_container.setProperty(key, "value", setting_value) setting_container.setProperty(key, "value", setting_value)
if len(um_node.getChildren()) > 0 and um_node.getMeshData() is None: if len(um_node.getChildren()) > 0 and um_node.getMeshData() is None:
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 = cast(CuraSceneNode, um_node.getChildren()[0])
else:
group_decorator = GroupDecorator() group_decorator = GroupDecorator()
um_node.addDecorator(group_decorator) um_node.addDecorator(group_decorator)
um_node.setSelectable(True) um_node.setSelectable(True)
@ -192,8 +200,8 @@ class ThreeMFReader(MeshReader):
um_node = self._convertSavitarNodeToUMNode(node, file_name) um_node = self._convertSavitarNodeToUMNode(node, file_name)
if um_node is None: if um_node is None:
continue 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() transform_matrix = Matrix()
mesh_data = um_node.getMeshData() mesh_data = um_node.getMeshData()
if mesh_data is not None: if mesh_data is not None:

View File

@ -172,7 +172,7 @@ class ImageReaderUI(QObject):
@pyqtSlot(int) @pyqtSlot(int)
def onColorModelChanged(self, value): def onColorModelChanged(self, value):
self.use_transparency_model = (value == 0) self.use_transparency_model = (value == 1)
@pyqtSlot(int) @pyqtSlot(int)
def onTransmittanceChanged(self, value): def onTransmittanceChanged(self, value):

View File

@ -0,0 +1,130 @@
# Cura PostProcessingPlugin
# Author: Mathias Lyngklip Kjeldgaard, Alexander Gee
# Date: July 31, 2019
# Modified: May 22, 2020
# 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):
def __init__(self):
super().__init__()
def getSettingDataString(self):
return """{
"name": "Display Progress On LCD",
"key": "DisplayProgressOnLCD",
"metadata": {},
"version": 2,
"settings":
{
"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":
{
"label": "Percentage",
"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 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("time_remaining")
output_percentage = self.getSettingValueByKey("percentage")
line_set = {}
if output_percentage or output_time:
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)
line_index = lines.index(line)
if output_time:
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")
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:
continue
current_time = self.getTimeValue(line)
line_index = lines.index(line)
if output_time:
# Here we calculate remaining time
self.outputTime(lines, line_index, total_time - current_time)
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
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

View File

@ -1,94 +0,0 @@
# Cura PostProcessingPlugin
# Author: Mathias Lyngklip Kjeldgaard
# Date: July 31, 2019
# Modified: November 26, 2019
# Description: This plugin displayes the remaining time on the LCD of the printer
# using the estimated print-time generated by Cura.
from ..Script import Script
import re
import datetime
class DisplayRemainingTimeOnLCD(Script):
def __init__(self):
super().__init__()
def getSettingDataString(self):
return """{
"name":"Display Remaining Time on LCD",
"key":"DisplayRemainingTimeOnLCD",
"metadata": {},
"version": 2,
"settings":
{
"TurnOn":
{
"label": "Enable",
"description": "When enabled, It will write Time Left: HHMMSS on the display. This is updated every layer.",
"type": "bool",
"default_value": false
}
}
}"""
def execute(self, data):
if self.getSettingValueByKey("TurnOn"):
total_time = 0
total_time_string = ""
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
elif line.startswith(";TIME_ELAPSED:"):
# 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
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
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
# 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
return data

View File

@ -45,13 +45,6 @@ class VersionUpgrade462to47(VersionUpgrade):
parser["general"]["visible_settings"] = ";".join( parser["general"]["visible_settings"] = ";".join(
set(parser["general"]["visible_settings"].split(";")).difference(_removed_settings)) 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() result = io.StringIO()
parser.write(result) parser.write(result)
return [filename], [result.getvalue()] return [filename], [result.getvalue()]
@ -168,6 +161,17 @@ class VersionUpgrade462to47(VersionUpgrade):
if "redo_layers" in script_parser["PauseAtHeight"]: if "redo_layers" in script_parser["PauseAtHeight"]:
script_parser["PauseAtHeight"]["redo_layer"] = str(int(script_parser["PauseAtHeight"]["redo_layers"]) > 0) 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. del script_parser["PauseAtHeight"]["redo_layers"] # Has been renamed to without the S.
# Migrate DisplayCompleteOnLCD to DisplayProgressOnLCD
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")
script_io = io.StringIO() script_io = io.StringIO()
script_parser.write(script_io) script_parser.write(script_io)
script_str = script_io.getvalue() script_str = script_io.getvalue()

View File

@ -7151,6 +7151,7 @@
"description": "Detect bridges and modify print speed, flow and fan settings while bridges are printed.", "description": "Detect bridges and modify print speed, flow and fan settings while bridges are printed.",
"type": "bool", "type": "bool",
"default_value": false, "default_value": false,
"resolve": "any(extruderValues('bridge_settings_enabled'))",
"settable_per_mesh": true, "settable_per_mesh": true,
"settable_per_extruder": false, "settable_per_extruder": false,
"settable_per_meshgroup": false "settable_per_meshgroup": false

View File

@ -866,6 +866,7 @@ UM.MainWindow
title: catalog.i18nc("@title:window", "What's New") title: catalog.i18nc("@title:window", "What's New")
model: CuraApplication.getWhatsNewPagesModel() model: CuraApplication.getWhatsNewPagesModel()
progressBarVisible: false progressBarVisible: false
visible: false
} }
Connections Connections

View File

@ -2,7 +2,7 @@
//Cura is released under the terms of the LGPLv3 or higher. //Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.1 import QtQuick.Controls 1.4
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
@ -24,7 +24,15 @@ Menu
title: modelData.name title: modelData.name
property var extruder: (base.activeMachine === null) ? null : activeMachine.extruderList[model.index] property var extruder: (base.activeMachine === null) ? null : activeMachine.extruderList[model.index]
NozzleMenu { title: Cura.MachineManager.activeDefinitionVariantsName; visible: Cura.MachineManager.activeMachine.hasVariants; extruderIndex: 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 MenuSeparator
{ {

View File

@ -85,8 +85,8 @@ UM.PreferencesPage
scaleTinyCheckbox.checked = boolCheck(UM.Preferences.getValue("mesh/scale_tiny_meshes")) scaleTinyCheckbox.checked = boolCheck(UM.Preferences.getValue("mesh/scale_tiny_meshes"))
UM.Preferences.resetPreference("cura/select_models_on_load") UM.Preferences.resetPreference("cura/select_models_on_load")
selectModelsOnLoadCheckbox.checked = boolCheck(UM.Preferences.getValue("cura/select_models_on_load")) selectModelsOnLoadCheckbox.checked = boolCheck(UM.Preferences.getValue("cura/select_models_on_load"))
UM.Preferences.resetPreference("cura/job_name_template") UM.Preferences.resetPreference("cura/jobname_prefix")
jobnameTemplateTextField.text = UM.Preferences.getValue("cura/job_name_template") prefixJobNameCheckbox.checked = boolCheck(UM.Preferences.getValue("cura/jobname_prefix"))
UM.Preferences.resetPreference("view/show_overhang"); UM.Preferences.resetPreference("view/show_overhang");
showOverhangCheckbox.checked = boolCheck(UM.Preferences.getValue("view/show_overhang")) showOverhangCheckbox.checked = boolCheck(UM.Preferences.getValue("view/show_overhang"))
UM.Preferences.resetPreference("view/show_xray_warning"); UM.Preferences.resetPreference("view/show_xray_warning");
@ -627,25 +627,14 @@ UM.PreferencesPage
{ {
width: childrenRect.width width: childrenRect.width
height: childrenRect.height 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 id: prefixJobNameCheckbox
text: catalog.i18nc("@option:check", "Add machine prefix to job name")
Label checked: boolCheck(UM.Preferences.getValue("cura/jobname_prefix"))
{ onCheckedChanged: UM.Preferences.setValue("cura/jobname_prefix", checked)
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)
}
} }
} }
@ -681,7 +670,7 @@ UM.PreferencesPage
ComboBox ComboBox
{ {
id: choiceOnOpenProjectDropDownButton id: choiceOnOpenProjectDropDownButton
width: 250 * screenScaleFactor width: 200 * screenScaleFactor
model: ListModel model: ListModel
{ {
@ -747,7 +736,7 @@ UM.PreferencesPage
ComboBox ComboBox
{ {
id: choiceOnProfileOverrideDropDownButton id: choiceOnProfileOverrideDropDownButton
width: 250 * screenScaleFactor width: 200 * screenScaleFactor
model: ListModel model: ListModel
{ {

View File

@ -22,22 +22,10 @@ Button
height: UM.Theme.getSize("section").height height: UM.Theme.getSize("section").height
color: color:
{ {
if (base.color) if (!base.enabled)
{
return base.color
}
else if (!base.enabled)
{ {
return UM.Theme.getColor("setting_category_disabled") 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) else if (base.hovered)
{ {
return UM.Theme.getColor("setting_category_hover") return UM.Theme.getColor("setting_category_hover")
@ -57,6 +45,21 @@ Button
property var focusItem: base property var focusItem: base
property bool expanded: definition.expanded 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 contentItem: Item
{ {
anchors.fill: parent anchors.fill: parent
@ -75,25 +78,7 @@ Button
textFormat: Text.PlainText textFormat: Text.PlainText
renderType: Text.NativeRendering renderType: Text.NativeRendering
font: UM.Theme.getFont("medium_bold") font: UM.Theme.getFont("medium_bold")
color: color: base.text_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")
}
}
fontSizeMode: Text.HorizontalFit fontSizeMode: Text.HorizontalFit
minimumPointSize: 8 minimumPointSize: 8
} }
@ -118,26 +103,7 @@ Button
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("thin_margin").width anchors.leftMargin: UM.Theme.getSize("thin_margin").width
color: color: base.text_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")
}
source: UM.Theme.getIcon(definition.icon) source: UM.Theme.getIcon(definition.icon)
width: UM.Theme.getSize("section_icon").width width: UM.Theme.getSize("section_icon").width
height: UM.Theme.getSize("section_icon").height height: UM.Theme.getSize("section_icon").height

View File

@ -156,7 +156,7 @@ Item
{ {
id: settingControls 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) spacing: Math.round(UM.Theme.getSize("thick_margin").height / 2)
anchors anchors

View File

@ -153,7 +153,7 @@ SettingItem
selectByMouse: true selectByMouse: true
maximumLength: (definition.type == "str" || definition.type == "[int]") ? -1 : 10 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 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

View File

@ -246,25 +246,18 @@ Item
} }
property int indexWithFocus: -1 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 : "" property string activeMachineId: Cura.MachineManager.activeMachine !== null ? Cura.MachineManager.activeMachine.id : ""
delegate: Loader delegate: Loader
{ {
id: delegate id: delegate
width: scrollView.width width: scrollView.width
height: provider.properties.enabled === "True" ? UM.Theme.getSize("section").height + 2 * UM.Theme.getSize("default_lining").height : 0 height: enabled ? contents.delegateHeight: 0
Behavior on height { NumberAnimation { duration: 100 } } Behavior on height { NumberAnimation { duration: 100 } }
opacity: provider.properties.enabled === "True" ? 1 : 0 opacity: enabled ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 100 } } Behavior on opacity { NumberAnimation { duration: 100 } }
enabled: enabled: provider.properties.enabled === "True"
{
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"
}
property var definition: model property var definition: model
property var settingDefinitionsModel: definitionsModel property var settingDefinitionsModel: definitionsModel
@ -272,10 +265,7 @@ Item
property var globalPropertyProvider: inheritStackProvider property var globalPropertyProvider: inheritStackProvider
property bool externalResetHandler: false property bool externalResetHandler: false
//Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989 asynchronous: true
//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"
active: model.type !== undefined active: model.type !== undefined
source: source:
@ -355,7 +345,7 @@ Item
id: provider id: provider
containerStackId: contents.activeMachineId containerStackId: contents.activeMachineId
key: model.key ? model.key : "" key: model.key
watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder", "resolve" ] watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder", "resolve" ]
storeIndex: 0 storeIndex: 0
removeUnusedValue: model.resolve === undefined removeUnusedValue: model.resolve === undefined

View File

@ -78,6 +78,10 @@ Item
{ {
base.activeY = y; 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 //Workaround since using ToolButton's onClicked would break the binding of the checked property, instead

View File

@ -40,6 +40,7 @@ Window
id: wizardPanel id: wizardPanel
anchors.fill: parent anchors.fill: parent
model: dialog.model model: dialog.model
visible: dialog.visible
} }
// Close this dialog when there's no more page to show // Close this dialog when there's no more page to show

View File

@ -71,7 +71,7 @@ Item
right: parent.right right: parent.right
} }
source: base.pageUrl source: base.pageUrl
enabled: base.visible active: base.visible
} }
} }
} }

View File

@ -1,6 +1,15 @@
[4.6.2] [4.6.2]
TODO Patch release to fix some bugs that emerged with 4.6.1.
* Persistent notifications in the Marketplace.
We fixed a frustrating bug where a package would keep issuing a badge notification to update, even after the package had been updated.
* Removed Ultibot from Marketplace login screen.
For professionalism, Ultibot has been asked to leave the Marketplace login screen. He's now gone from everything.
* Ultimaker 2+ Z-hop.
The Ultimaker 2+ included an unwanted travel move that could drag purged material into the start of a print. This is now fixed.
[4.6.1] [4.6.1]
@ -140,7 +149,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. 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. * 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. * Property checks on instance containers.
A new speed optimization for reading setting values from profiles. A new speed optimization for reading setting values from profiles.

View File

@ -99,13 +99,9 @@
"setting_category": [75, 80, 83, 255], "setting_category": [75, 80, 83, 255],
"setting_category_disabled": [75, 80, 83, 255], "setting_category_disabled": [75, 80, 83, 255],
"setting_category_hover": [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_text": [255, 255, 255, 152],
"setting_category_disabled_text": [255, 255, 255, 101], "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_text": [255, 255, 255, 204],
"setting_category_active_hover_text": [255, 255, 255, 204],
"setting_category_border": [39, 44, 48, 0], "setting_category_border": [39, 44, 48, 0],
"setting_category_disabled_border": [39, 44, 48, 0], "setting_category_disabled_border": [39, 44, 48, 0],
"setting_category_hover_border": [12, 169, 227, 255], "setting_category_hover_border": [12, 169, 227, 255],

View File

@ -274,13 +274,9 @@
"setting_category": [240, 240, 240, 255], "setting_category": [240, 240, 240, 255],
"setting_category_disabled": [255, 255, 255, 255], "setting_category_disabled": [255, 255, 255, 255],
"setting_category_hover": [232, 242, 252, 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_text": [35, 35, 35, 255],
"setting_category_disabled_text": [24, 41, 77, 101], "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_text": [35, 35, 35, 255],
"setting_category_active_hover_text": [35, 35, 35, 255],
"setting_category_border": [240, 240, 240, 255], "setting_category_border": [240, 240, 240, 255],
"setting_category_disabled_border": [240, 240, 240, 255], "setting_category_disabled_border": [240, 240, 240, 255],
"setting_category_hover_border": [50, 130, 255, 255], "setting_category_hover_border": [50, 130, 255, 255],
@ -502,6 +498,7 @@
"extruder_icon": [2.33, 2.33], "extruder_icon": [2.33, 2.33],
"section": [0.0, 2], "section": [0.0, 2],
"section_control": [0, 1],
"section_icon": [1.6, 1.6], "section_icon": [1.6, 1.6],
"section_icon_column": [2.8, 0.0], "section_icon_column": [2.8, 0.0],
"rating_star": [1.0, 1.0], "rating_star": [1.0, 1.0],

View File

@ -8,13 +8,6 @@ from unittest.mock import MagicMock, patch
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType 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: def getPrintInformation(printer_name) -> PrintInformation:
mock_application = MagicMock(name = "mock_application") mock_application = MagicMock(name = "mock_application")
@ -26,7 +19,7 @@ def getPrintInformation(printer_name) -> PrintInformation:
mocked_extruder_stack.material = mocked_material mocked_extruder_stack.material = mocked_material
mock_application.getInstance = MagicMock(return_value = mock_application) 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 = MagicMock()
global_container_stack.definition.getName = MagicMock(return_value = printer_name) global_container_stack.definition.getName = MagicMock(return_value = printer_name)