From 852e59f310017978360cdea217afb498b55aeddc Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 9 Oct 2017 12:24:08 +0200 Subject: [PATCH 01/19] Fix retrieving default values with "extruderValue()" CURA-4358 Use evaluation context to override the default extruderValue() function with getDefaultExtruderValue() so it can get the correct default values from each extruder. --- cura/Settings/ExtruderManager.py | 17 +++++++++++++++++ cura/Settings/UserChangesModel.py | 13 +++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 9e17ce028d..1c01b1fc8a 100755 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -16,6 +16,7 @@ from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.SettingFunction import SettingFunction from UM.Settings.ContainerStack import ContainerStack from UM.Settings.Interfaces import DefinitionContainerInterface +from UM.Settings.PropertyEvaluationContext import PropertyEvaluationContext from typing import Optional, List, TYPE_CHECKING, Union if TYPE_CHECKING: @@ -620,6 +621,22 @@ class ExtruderManager(QObject): return value + ## Get the default value from the given extruder. This function will skip the user settings container. + @staticmethod + def getDefaultExtruderValue(extruder_index, key): + extruder = ExtruderManager.getInstance().getExtruderStack(extruder_index) + context = PropertyEvaluationContext() + context.context["evaluate_from_container_index"] = 1 # skip the user settings container + + if extruder: + value = extruder.getRawProperty(key, "value", context = context) + if isinstance(value, SettingFunction): + value = value(extruder, context = context) + else: # Just a value from global. + value = Application.getInstance().getGlobalContainerStack().getProperty(key, "value", context = context) + + return value + ## Get the resolve value or value for a given key # # This is the effective value for a given key, it is used for values in the global stack. diff --git a/cura/Settings/UserChangesModel.py b/cura/Settings/UserChangesModel.py index 8b61186650..d47468b808 100644 --- a/cura/Settings/UserChangesModel.py +++ b/cura/Settings/UserChangesModel.py @@ -6,6 +6,7 @@ from cura.Settings.ExtruderManager import ExtruderManager from UM.Settings.ContainerRegistry import ContainerRegistry from UM.i18n import i18nCatalog from UM.Settings.SettingFunction import SettingFunction +from UM.Settings.PropertyEvaluationContext import PropertyEvaluationContext from collections import OrderedDict import os @@ -66,8 +67,12 @@ class UserChangesModel(ListModel): containers.extend(latest_stack.getContainers()) latest_stack = latest_stack.getNextStack() - # Drop the user container. + # Override "getExtruderValue" with "getDefaultExtruderValue" so we can get the default values user_changes = containers.pop(0) + default_value_resolve_context = PropertyEvaluationContext(stack) + default_value_resolve_context.context["override_operators"] = { + "extruderValue": ExtruderManager.getDefaultExtruderValue + } for setting_key in user_changes.getAllKeys(): original_value = None @@ -90,16 +95,16 @@ class UserChangesModel(ListModel): for container in containers: if stack == global_stack: - resolve = global_stack.getProperty(setting_key, "resolve") + resolve = global_stack.getProperty(setting_key, "resolve", default_value_resolve_context) if resolve is not None: original_value = resolve break - original_value = container.getProperty(setting_key, "value") + original_value = container.getProperty(setting_key, "value", default_value_resolve_context) # If a value is a function, ensure it's called with the stack it's in. if isinstance(original_value, SettingFunction): - original_value = original_value(stack) + original_value = original_value(stack, default_value_resolve_context) if original_value is not None: break From 19e93362141631e41e7fc42558207854ddcedc22 Mon Sep 17 00:00:00 2001 From: "A.Sasin" Date: Tue, 10 Oct 2017 09:43:43 +0200 Subject: [PATCH 02/19] Revert "Adjust column width for Materials "Print Settings" page" This reverts commit 7b6faf0030d9455f772c364ce4c9f16ae0bf1e21. --- resources/qml/Preferences/MaterialView.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/MaterialView.qml index b13ce1aadf..c1750b2342 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/MaterialView.qml @@ -16,8 +16,8 @@ TabView property bool editingEnabled: false; property string currency: UM.Preferences.getValue("cura/currency") ? UM.Preferences.getValue("cura/currency") : "€" - property real firstColumnWidth: (width * 0.50) | 0 - property real secondColumnWidth: (width * 0.40) | 0 + property real firstColumnWidth: (width * 0.45) | 0 + property real secondColumnWidth: (width * 0.45) | 0 property string containerId: "" property var materialPreferenceValues: UM.Preferences.getValue("cura/material_settings") ? JSON.parse(UM.Preferences.getValue("cura/material_settings")) : {} From 71e8de13a83198846c9758803ae1f4f9349b6f91 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 11 Oct 2017 11:05:01 +0200 Subject: [PATCH 03/19] Fix retrieving setting values with "extruderValues()" and "resolveOrValue()" CURA-4358 Using the context for override the extruderValues() and resolveOrValue() functions, for getting the correct values. Also indicate in the context to skip the first container in the stacks (user container) --- cura/Settings/ExtruderManager.py | 77 ++++++++++++++++++++++++++++++- cura/Settings/GlobalStack.py | 14 +++--- cura/Settings/UserChangesModel.py | 5 +- 3 files changed, 87 insertions(+), 9 deletions(-) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 1c01b1fc8a..c8daca7f92 100755 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -588,6 +588,46 @@ class ExtruderManager(QObject): return result + ## Get all extruder values for a certain setting. This function will skip the user settings container. + # + # This is exposed to SettingFunction so it can be used in value functions. + # + # \param key The key of the setting to retrieve values for. + # + # \return A list of values for all extruders. If an extruder does not have a value, it will not be in the list. + # If no extruder has the value, the list will contain the global value. + @staticmethod + def getDefaultExtruderValues(key): + global_stack = Application.getInstance().getGlobalContainerStack() + context = PropertyEvaluationContext(global_stack) + context.context["evaluate_from_container_index"] = 1 # skip the user settings container + context.context["override_operators"] = { + "extruderValue": ExtruderManager.getDefaultExtruderValue, + "extruderValues": ExtruderManager.getDefaultExtruderValues, + "resolveOrValue": ExtruderManager.getDefaultResolveOrValue + } + + result = [] + for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()): + # only include values from extruders that are "active" for the current machine instance + if int(extruder.getMetaDataEntry("position")) >= global_stack.getProperty("machine_extruder_count", "value", context = context): + continue + + value = extruder.getRawProperty(key, "value", context = context) + + if value is None: + continue + + if isinstance(value, SettingFunction): + value = value(extruder, context = context) + + result.append(value) + + if not result: + result.append(global_stack.getProperty(key, "value", context = context)) + + return result + ## Get all extruder values for a certain setting. # # This is exposed to qml for display purposes @@ -622,11 +662,24 @@ class ExtruderManager(QObject): return value ## Get the default value from the given extruder. This function will skip the user settings container. + # + # This is exposed to SettingFunction to use in value functions. + # + # \param extruder_index The index of the extruder to get the value from. + # \param key The key of the setting to get the value of. + # + # \return The value of the setting for the specified extruder or for the + # global stack if not found. @staticmethod def getDefaultExtruderValue(extruder_index, key): extruder = ExtruderManager.getInstance().getExtruderStack(extruder_index) - context = PropertyEvaluationContext() + context = PropertyEvaluationContext(extruder) context.context["evaluate_from_container_index"] = 1 # skip the user settings container + context.context["override_operators"] = { + "extruderValue": ExtruderManager.getDefaultExtruderValue, + "extruderValues": ExtruderManager.getDefaultExtruderValues, + "resolveOrValue": ExtruderManager.getDefaultResolveOrValue + } if extruder: value = extruder.getRawProperty(key, "value", context = context) @@ -650,3 +703,25 @@ class ExtruderManager(QObject): resolved_value = global_stack.getProperty(key, "value") return resolved_value + + ## Get the resolve value or value for a given key without looking the first container (user container) + # + # This is the effective value for a given key, it is used for values in the global stack. + # This is exposed to SettingFunction to use in value functions. + # \param key The key of the setting to get the value of. + # + # \return The effective value + @staticmethod + def getDefaultResolveOrValue(key): + global_stack = Application.getInstance().getGlobalContainerStack() + context = PropertyEvaluationContext(global_stack) + context.context["evaluate_from_container_index"] = 1 # skip the user settings container + context.context["override_operators"] = { + "extruderValue": ExtruderManager.getDefaultExtruderValue, + "extruderValues": ExtruderManager.getDefaultExtruderValues, + "resolveOrValue": ExtruderManager.getDefaultResolveOrValue + } + + resolved_value = global_stack.getProperty(key, "value", context = context) + + return resolved_value diff --git a/cura/Settings/GlobalStack.py b/cura/Settings/GlobalStack.py index 2eb951f721..88218c2f1e 100755 --- a/cura/Settings/GlobalStack.py +++ b/cura/Settings/GlobalStack.py @@ -96,18 +96,18 @@ class GlobalStack(CuraContainerStack): if not self.definition.findDefinitions(key = key): return None + if context is None: + context = PropertyEvaluationContext() + context.pushContainer(self) + # Handle the "resolve" property. - if self._shouldResolve(key, property_name): + if self._shouldResolve(key, property_name, context): self._resolving_settings.add(key) resolve = super().getProperty(key, "resolve", context) self._resolving_settings.remove(key) if resolve is not None: return resolve - if context is None: - context = PropertyEvaluationContext() - context.pushContainer(self) - # Handle the "limit_to_extruder" property. limit_to_extruder = super().getProperty(key, "limit_to_extruder", context) if limit_to_extruder is not None: @@ -151,7 +151,7 @@ class GlobalStack(CuraContainerStack): # Determine whether or not we should try to get the "resolve" property instead of the # requested property. - def _shouldResolve(self, key: str, property_name: str) -> bool: + def _shouldResolve(self, key: str, property_name: str, context: Optional[PropertyEvaluationContext] = None) -> bool: if property_name is not "value": # Do not try to resolve anything but the "value" property return False @@ -163,7 +163,7 @@ class GlobalStack(CuraContainerStack): # track all settings that are being resolved. return False - setting_state = super().getProperty(key, "state") + setting_state = super().getProperty(key, "state", context = context) if setting_state is not None and setting_state != InstanceState.Default: # When the user has explicitly set a value, we should ignore any resolve and # just return that value. diff --git a/cura/Settings/UserChangesModel.py b/cura/Settings/UserChangesModel.py index d47468b808..93274d61c9 100644 --- a/cura/Settings/UserChangesModel.py +++ b/cura/Settings/UserChangesModel.py @@ -70,8 +70,11 @@ class UserChangesModel(ListModel): # Override "getExtruderValue" with "getDefaultExtruderValue" so we can get the default values user_changes = containers.pop(0) default_value_resolve_context = PropertyEvaluationContext(stack) + default_value_resolve_context.context["evaluate_from_container_index"] = 1 # skip the user settings container default_value_resolve_context.context["override_operators"] = { - "extruderValue": ExtruderManager.getDefaultExtruderValue + "extruderValue": ExtruderManager.getDefaultExtruderValue, + "extruderValues": ExtruderManager.getDefaultExtruderValues, + "resolveOrValue": ExtruderManager.getDefaultResolveOrValue } for setting_key in user_changes.getAllKeys(): From 3a7fbdb1736d8a7799ac5910adf2f450617fa9e4 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 11 Oct 2017 16:47:40 +0200 Subject: [PATCH 04/19] Changed parseInt to Math.floor --- resources/qml/Preferences/MaterialView.qml | 6 +-- resources/qml/Preferences/MaterialsPage.qml | 2 +- resources/qml/PrintMonitor.qml | 24 +++++----- resources/qml/Settings/SettingView.qml | 8 ++-- resources/qml/Sidebar.qml | 10 ++--- resources/qml/SidebarHeader.qml | 28 ++++++------ resources/qml/SidebarSimple.qml | 50 ++++++++++----------- 7 files changed, 64 insertions(+), 64 deletions(-) diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/MaterialView.qml index 04a65393e0..143f29c86e 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/MaterialView.qml @@ -108,15 +108,15 @@ TabView { width: scrollView.columnWidth; height: parent.rowHeight; - spacing: parseInt(UM.Theme.getSize("default_margin").width/2) + spacing: Math.floor(UM.Theme.getSize("default_margin").width/2) Rectangle { id: colorSelector color: properties.color_code - width: parseInt(colorLabel.height * 0.75) - height: parseInt(colorLabel.height * 0.75) + width: Math.floor(colorLabel.height * 0.75) + height: Math.floor(colorLabel.height * 0.75) border.width: UM.Theme.getSize("default_lining").height anchors.verticalCenter: parent.verticalCenter diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index b260f3397f..5e014faf24 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -67,7 +67,7 @@ UM.ManagementPage } Label { - width: parseInt((parent.width * 0.3)) + width: Math.floor((parent.width * 0.3)) text: model.metadata.material elide: Text.ElideRight font.italic: model.id == activeId diff --git a/resources/qml/PrintMonitor.qml b/resources/qml/PrintMonitor.qml index 497e848bed..4bf4b44aed 100644 --- a/resources/qml/PrintMonitor.qml +++ b/resources/qml/PrintMonitor.qml @@ -24,7 +24,7 @@ Column { id: connectedPrinterHeader width: parent.width - height: parseInt(childrenRect.height + UM.Theme.getSize("default_margin").height * 2) + height: Math.floor(childrenRect.height + UM.Theme.getSize("default_margin").height * 2) color: UM.Theme.getColor("setting_category") Label @@ -82,7 +82,7 @@ Column { id: extruderRectangle color: UM.Theme.getColor("sidebar") - width: index == machineExtruderCount.properties.value - 1 && index % 2 == 0 ? extrudersGrid.width : parseInt(extrudersGrid.width / 2 - UM.Theme.getSize("sidebar_lining_thin").width / 2) + width: index == machineExtruderCount.properties.value - 1 && index % 2 == 0 ? extrudersGrid.width : Math.floor(extrudersGrid.width / 2 - UM.Theme.getSize("sidebar_lining_thin").width / 2) height: UM.Theme.getSize("sidebar_extruder_box").height Label //Extruder name. @@ -162,8 +162,8 @@ Column Rectangle //Material colour indication. { id: materialColor - width: parseInt(materialName.height * 0.75) - height: parseInt(materialName.height * 0.75) + width: Math.floor(materialName.height * 0.75) + height: Math.floor(materialName.height * 0.75) radius: width / 2 color: (connectedPrinter != null && connectedPrinter.materialColors[index] != null && connectedPrinter.materialIds[index] != "") ? connectedPrinter.materialColors[index] : "#00000000" border.width: UM.Theme.getSize("default_lining").width @@ -357,7 +357,7 @@ Column color: !enabled ? UM.Theme.getColor("setting_control_disabled") : showError ? UM.Theme.getColor("setting_validation_error_background") : UM.Theme.getColor("setting_validation_ok") property var showError: { - if(bedTemperature.properties.maximum_value != "None" && bedTemperature.properties.maximum_value < parseInt(preheatTemperatureInput.text)) + if(bedTemperature.properties.maximum_value != "None" && bedTemperature.properties.maximum_value < Math.floor(preheatTemperatureInput.text)) { return true; } else @@ -475,7 +475,7 @@ Column visible: preheatCountdown.visible source: UM.Theme.getIcon("print_time") anchors.right: preheatCountdown.left - anchors.rightMargin: parseInt(UM.Theme.getSize("default_margin").width / 2) + anchors.rightMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2) anchors.verticalCenter: preheatCountdown.verticalCenter } @@ -527,15 +527,15 @@ Column { return true; //Can always cancel if the timer is running. } - if (bedTemperature.properties.minimum_value != "None" && parseInt(preheatTemperatureInput.text) < parseInt(bedTemperature.properties.minimum_value)) + if (bedTemperature.properties.minimum_value != "None" && Math.floor(preheatTemperatureInput.text) < Math.floor(bedTemperature.properties.minimum_value)) { return false; //Target temperature too low. } - if (bedTemperature.properties.maximum_value != "None" && parseInt(preheatTemperatureInput.text) > parseInt(bedTemperature.properties.maximum_value)) + if (bedTemperature.properties.maximum_value != "None" && Math.floor(preheatTemperatureInput.text) > Math.floor(bedTemperature.properties.maximum_value)) { return false; //Target temperature too high. } - if (parseInt(preheatTemperatureInput.text) == 0) + if (Math.floor(preheatTemperatureInput.text) == 0) { return false; //Setting the temperature to 0 is not allowed (since that cancels the pre-heating). } @@ -708,13 +708,13 @@ Column Row { height: UM.Theme.getSize("setting_control").height - width: parseInt(base.width - 2 * UM.Theme.getSize("default_margin").width) + width: Math.floor(base.width - 2 * UM.Theme.getSize("default_margin").width) anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_margin").width Label { - width: parseInt(parent.width * 0.4) + width: Math.floor(parent.width * 0.4) anchors.verticalCenter: parent.verticalCenter text: label color: connectedPrinter != null && connectedPrinter.acceptsCommands ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text") @@ -723,7 +723,7 @@ Column } Label { - width: parseInt(parent.width * 0.6) + width: Math.floor(parent.width * 0.6) anchors.verticalCenter: parent.verticalCenter text: value color: connectedPrinter != null && connectedPrinter.acceptsCommands ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text") diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index a1136437dd..56fd789564 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -39,7 +39,7 @@ Item { id: globalProfileLabel text: catalog.i18nc("@label","Profile:"); - width: parseInt(parent.width * 0.45 - UM.Theme.getSize("sidebar_margin").width - 2) + width: Math.floor(parent.width * 0.45 - UM.Theme.getSize("sidebar_margin").width - 2) font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); verticalAlignment: Text.AlignVCenter @@ -63,7 +63,7 @@ Item } enabled: !header.currentExtruderVisible || header.currentExtruderIndex > -1 - width: parseInt(parent.width * 0.55) + width: Math.floor(parent.width * 0.55) height: UM.Theme.getSize("setting_control").height anchors.left: globalProfileLabel.right anchors.right: parent.right @@ -77,8 +77,8 @@ Item id: customisedSettings visible: Cura.MachineManager.hasUserSettings - height: parseInt(parent.height * 0.6) - width: parseInt(parent.height * 0.6) + height: Math.floor(parent.height * 0.6) + width: Math.floor(parent.height * 0.6) anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index a2d822f6b6..475e36d2dc 100755 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -121,7 +121,7 @@ Rectangle anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width anchors.top: headerSeparator.bottom anchors.topMargin: UM.Theme.getSize("sidebar_margin").height - width: parseInt(parent.width * 0.45) + width: Math.floor(parent.width * 0.45) font: UM.Theme.getFont("large") color: UM.Theme.getColor("text") visible: !monitoringPrint && !hideView @@ -130,7 +130,7 @@ Rectangle Rectangle { id: settingsModeSelection color: "transparent" - width: parseInt(parent.width * 0.55) + width: Math.floor(parent.width * 0.55) height: UM.Theme.getSize("sidebar_header_mode_toggle").height anchors.right: parent.right anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width @@ -154,7 +154,7 @@ Rectangle anchors.left: parent.left anchors.leftMargin: model.index * (settingsModeSelection.width / 2) anchors.verticalCenter: parent.verticalCenter - width: parseInt(0.5 * parent.width) + width: Math.floor(0.5 * parent.width) text: model.text exclusiveGroup: modeMenuGroup; checkable: true; @@ -310,7 +310,7 @@ Rectangle height: UM.Theme.getSize("sidebar_lining").height color: UM.Theme.getColor("sidebar_lining") anchors.bottom: printSpecs.top - anchors.bottomMargin: parseInt(UM.Theme.getSize("sidebar_margin").height * 2 + UM.Theme.getSize("progressbar").height + UM.Theme.getFont("default_bold").pixelSize) + anchors.bottomMargin: Math.floor(UM.Theme.getSize("sidebar_margin").height * 2 + UM.Theme.getSize("progressbar").height + UM.Theme.getFont("default_bold").pixelSize) } Rectangle @@ -490,7 +490,7 @@ Rectangle }) sidebarContents.push({ "item": modesListModel.get(base.currentModeIndex).item, "immediate": true }); - var index = parseInt(UM.Preferences.getValue("cura/active_mode")) + var index = Math.floor(UM.Preferences.getValue("cura/active_mode")) if(index) { currentModeIndex = index; diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index b30e1e0c1c..aa0f8a3f38 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -17,7 +17,7 @@ Column property int currentExtruderIndex: ExtruderManager.activeExtruderIndex; property bool currentExtruderVisible: extrudersList.visible; - spacing: UM.Theme.getSize("sidebar_margin").width * 0.9 + spacing: Math.floor(UM.Theme.getSize("sidebar_margin").width * 0.9) signal showTooltip(Item item, point location, string text) signal hideTooltip() @@ -52,15 +52,15 @@ Column { id: extruderSelectionRow width: parent.width - height: UM.Theme.getSize("sidebar_tabs").height * 2 / 3 + height: Math.floor(UM.Theme.getSize("sidebar_tabs").height * 2 / 3) visible: machineExtruderCount.properties.value > 1 && !sidebar.monitoringPrint anchors { left: parent.left - leftMargin: UM.Theme.getSize("sidebar_margin").width * 0.7 + leftMargin: Math.floor(UM.Theme.getSize("sidebar_margin").width * 0.7) right: parent.right - rightMargin: UM.Theme.getSize("sidebar_margin").width * 0.7 + rightMargin: Math.floor(UM.Theme.getSize("sidebar_margin").width * 0.7) topMargin: UM.Theme.getSize("sidebar_margin").height } @@ -70,15 +70,15 @@ Column property var index: 0 height: UM.Theme.getSize("sidebar_header_mode_tabs").height - width: parent.width + width: Math.floor(parent.width) boundsBehavior: Flickable.StopAtBounds anchors { left: parent.left - leftMargin: UM.Theme.getSize("default_margin").width / 2 + leftMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2) right: parent.right - rightMargin: UM.Theme.getSize("default_margin").width / 2 + rightMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2) verticalCenter: parent.verticalCenter } @@ -134,7 +134,7 @@ Column width: { var extruderTextWidth = extruderStaticText.visible ? extruderStaticText.width : 0; var iconWidth = extruderIconItem.width; - return parseInt(extruderTextWidth + iconWidth + UM.Theme.getSize("default_margin").width / 2); + return Math.floor(extruderTextWidth + iconWidth + UM.Theme.getSize("default_margin").width / 2); } // Static text "Extruder" @@ -166,7 +166,7 @@ Column var minimumWidth = control.width < UM.Theme.getSize("button").width ? control.width : UM.Theme.getSize("button").width; var minimumHeight = control.height < UM.Theme.getSize("button").height ? control.height : UM.Theme.getSize("button").height; var minimumSize = minimumWidth < minimumHeight ? minimumWidth : minimumHeight; - minimumSize -= parseInt(UM.Theme.getSize("default_margin").width / 2); + minimumSize -= Math.floor(UM.Theme.getSize("default_margin").width / 2); return minimumSize; } @@ -254,7 +254,7 @@ Column { id: materialLabel text: catalog.i18nc("@label","Material"); - width: parseInt(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) + width: Math.floor(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); } @@ -310,7 +310,7 @@ Column { id: printCoreLabel text: Cura.MachineManager.activeDefinitionVariantsName; - width: parseInt(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) + width: Math.floor(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); } @@ -322,7 +322,7 @@ Column visible: Cura.MachineManager.hasVariants height: UM.Theme.getSize("setting_control").height - width: parseInt(parent.width * 0.7 + UM.Theme.getSize("sidebar_margin").width) + width: Math.floor(parent.width * 0.7 + UM.Theme.getSize("sidebar_margin").width) anchors.right: parent.right style: UM.Theme.styles.sidebar_header_button activeFocusOnPress: true; @@ -335,7 +335,7 @@ Column Item { id: materialInfoRow - height: parseInt(UM.Theme.getSize("sidebar_setup").height / 2) + height: Math.floor(UM.Theme.getSize("sidebar_setup").height / 2) visible: (Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials) && !sidebar.monitoringPrint && !sidebar.hideSettings anchors @@ -349,7 +349,7 @@ Column Item { height: UM.Theme.getSize("sidebar_setup").height anchors.right: parent.right - width: parseInt(parent.width * 0.7 + UM.Theme.getSize("sidebar_margin").width) + width: Math.floor(parent.width * 0.7 + UM.Theme.getSize("sidebar_margin").width) UM.RecolorImage { id: warningImage diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index 114a53eda1..59972bbf99 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -175,7 +175,7 @@ Item { anchors.verticalCenter: parent.verticalCenter anchors.top: parent.top - anchors.topMargin: parseInt(UM.Theme.getSize("sidebar_margin").height / 2) + anchors.topMargin: Math.floor(UM.Theme.getSize("sidebar_margin").height / 2) color: (Cura.MachineManager.activeMachine != null && Cura.ProfilesModel.getItem(index).available) ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") text: { @@ -194,13 +194,13 @@ Item // Make sure the text aligns correctly with each tick if (qualityModel.totalTicks == 0) { // If there is only one tick, align it centrally - return parseInt(((base.width * 0.55) - width) / 2) + return Math.floor(((base.width * 0.55) - width) / 2) } else if (index == 0) { return (base.width * 0.55 / qualityModel.totalTicks) * index } else if (index == qualityModel.totalTicks) { return (base.width * 0.55 / qualityModel.totalTicks) * index - width } else { - return parseInt((base.width * 0.55 / qualityModel.totalTicks) * index - (width / 2)) + return Math.floor((base.width * 0.55 / qualityModel.totalTicks) * index - (width / 2)) } } } @@ -361,7 +361,7 @@ Item anchors.topMargin: UM.Theme.getSize("sidebar_margin").height * 2 anchors.left: parent.left - width: parseInt(UM.Theme.getSize("sidebar").width * .45 - UM.Theme.getSize("sidebar_margin").width) + width: Math.floor(UM.Theme.getSize("sidebar").width * .45 - UM.Theme.getSize("sidebar_margin").width) Label { @@ -371,7 +371,7 @@ Item color: UM.Theme.getColor("text") anchors.top: parent.top - anchors.topMargin: parseInt(UM.Theme.getSize("sidebar_margin").height * 1.7) + anchors.topMargin: Math.floor(UM.Theme.getSize("sidebar_margin").height * 1.7) anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width } @@ -382,7 +382,7 @@ Item id: infillCellRight height: infillSlider.height + UM.Theme.getSize("sidebar_margin").height + enableGradualInfillCheckBox.visible * (enableGradualInfillCheckBox.height + UM.Theme.getSize("sidebar_margin").height) - width: parseInt(UM.Theme.getSize("sidebar").width * .55) + width: Math.floor(UM.Theme.getSize("sidebar").width * .55) anchors.left: infillCellLeft.right anchors.top: infillCellLeft.top @@ -393,10 +393,10 @@ Item //anchors.top: parent.top anchors.left: infillSlider.left - anchors.leftMargin: parseInt((infillSlider.value / infillSlider.stepSize) * (infillSlider.width / (infillSlider.maximumValue / infillSlider.stepSize)) - 10 * screenScaleFactor) + anchors.leftMargin: Math.floor((infillSlider.value / infillSlider.stepSize) * (infillSlider.width / (infillSlider.maximumValue / infillSlider.stepSize)) - 10 * screenScaleFactor) anchors.right: parent.right - text: parseInt(infillDensity.properties.value) + "%" + text: Math.floor(infillDensity.properties.value) + "%" horizontalAlignment: Text.AlignLeft color: infillSlider.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") @@ -406,7 +406,7 @@ Item Binding { target: infillSlider property: "value" - value: parseInt(infillDensity.properties.value) + value: Math.floor(infillDensity.properties.value) } Slider @@ -419,7 +419,7 @@ Item anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width height: UM.Theme.getSize("sidebar_margin").height - width: parseInt(infillCellRight.width - UM.Theme.getSize("sidebar_margin").width - style.handleWidth) + width: Math.floor(infillCellRight.width - UM.Theme.getSize("sidebar_margin").width - style.handleWidth) minimumValue: 0 maximumValue: 100 @@ -427,15 +427,15 @@ Item tickmarksEnabled: true // disable slider when gradual support is enabled - enabled: parseInt(infillSteps.properties.value) == 0 + enabled: Math.floor(infillSteps.properties.value) == 0 // set initial value from stack - value: parseInt(infillDensity.properties.value) + value: Math.floor(infillDensity.properties.value) onValueChanged: { // Don't round the value if it's already the same - if (parseInt(infillDensity.properties.value) == infillSlider.value) { + if (Math.floor(infillDensity.properties.value) == infillSlider.value) { return } @@ -504,7 +504,7 @@ Item anchors.right: parent.right anchors.top: parent.top - anchors.topMargin: parseInt(UM.Theme.getSize("sidebar_margin").height / 2) + anchors.topMargin: Math.floor(UM.Theme.getSize("sidebar_margin").height / 2) // we loop over all density icons and only show the one that has the current density and steps Repeater @@ -515,8 +515,8 @@ Item property int activeIndex: { for (var i = 0; i < infillModel.count; i++) { - var density = parseInt(infillDensity.properties.value) - var steps = parseInt(infillSteps.properties.value) + var density = Math.floor(infillDensity.properties.value) + var steps = Math.floor(infillSteps.properties.value) var infillModelItem = infillModel.get(i) if (density >= infillModelItem.percentageMin @@ -555,13 +555,13 @@ Item property alias _hovered: enableGradualInfillMouseArea.containsMouse anchors.top: infillSlider.bottom - anchors.topMargin: parseInt(UM.Theme.getSize("sidebar_margin").height / 2) // closer to slider since it belongs to the same category + anchors.topMargin: Math.floor(UM.Theme.getSize("sidebar_margin").height / 2) // closer to slider since it belongs to the same category anchors.left: infillCellRight.left style: UM.Theme.styles.checkbox enabled: base.settingsEnabled visible: infillSteps.properties.enabled == "True" - checked: parseInt(infillSteps.properties.value) > 0 + checked: Math.floor(infillSteps.properties.value) > 0 MouseArea { id: enableGradualInfillMouseArea @@ -570,18 +570,18 @@ Item hoverEnabled: true enabled: true - property var previousInfillDensity: parseInt(infillDensity.properties.value) + property var previousInfillDensity: Math.floor(infillDensity.properties.value) onClicked: { // Set to 90% only when enabling gradual infill - if (parseInt(infillSteps.properties.value) == 0) { - previousInfillDensity = parseInt(infillDensity.properties.value) + if (Math.floor(infillSteps.properties.value) == 0) { + previousInfillDensity = Math.floor(infillDensity.properties.value) infillDensity.setPropertyValue("value", String(90)) } else { infillDensity.setPropertyValue("value", String(previousInfillDensity)) } - infillSteps.setPropertyValue("value", (parseInt(infillSteps.properties.value) == 0) ? 5 : 0) + infillSteps.setPropertyValue("value", (Math.floor(infillSteps.properties.value) == 0) ? 5 : 0) } onEntered: { @@ -597,7 +597,7 @@ Item Label { id: gradualInfillLabel anchors.left: enableGradualInfillCheckBox.right - anchors.leftMargin: parseInt(UM.Theme.getSize("sidebar_margin").width / 2) + anchors.leftMargin: Math.floor(UM.Theme.getSize("sidebar_margin").width / 2) text: catalog.i18nc("@label", "Enable gradual") font: UM.Theme.getFont("default") color: UM.Theme.getColor("text") @@ -658,7 +658,7 @@ Item visible: enableSupportCheckBox.visible anchors.top: infillCellRight.bottom - anchors.topMargin: parseInt(UM.Theme.getSize("sidebar_margin").height * 1.5) + anchors.topMargin: Math.floor(UM.Theme.getSize("sidebar_margin").height * 1.5) anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width anchors.verticalCenter: enableSupportCheckBox.verticalCenter @@ -867,7 +867,7 @@ Item { id: tipsCell anchors.top: adhesionCheckBox.visible ? adhesionCheckBox.bottom : (enableSupportCheckBox.visible ? supportExtruderCombobox.bottom : infillCellRight.bottom) - anchors.topMargin: parseInt(UM.Theme.getSize("sidebar_margin").height * 2) + anchors.topMargin: Math.floor(UM.Theme.getSize("sidebar_margin").height * 2) anchors.left: parent.left width: parent.width height: tipsText.contentHeight * tipsText.lineCount From 052ea7d90aa461ea9f1fb0194eb2709057243ff5 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 12 Oct 2017 07:57:20 +0200 Subject: [PATCH 05/19] Force use and update the job name with the loaded project file CURA-4348 - If no project is loaded beforehand and then a model file is loaded, the job name should be determined with the current machine name and the first loaded model name. - If a project is loaded, the job name should be the same as the project name, and it should not change until another project is loaded. --- cura/CuraApplication.py | 2 ++ cura/PrintInformation.py | 14 ++++++++++++-- plugins/3MFReader/ThreeMFWorkspaceReader.py | 6 ++++++ resources/qml/OpenFilesIncludingProjectsDialog.qml | 2 -- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index fc7edb8714..e34bdc6908 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -125,6 +125,8 @@ class CuraApplication(QtApplication): # Cura will always show the Add Machine Dialog upon start. stacksValidationFinished = pyqtSignal() # Emitted whenever a validation is finished + projectFileLoaded = pyqtSignal(str) # Emitted whenever a project file is loaded + def __init__(self): # this list of dir names will be used by UM to detect an old cura directory for dir_name in ["extruders", "machine_instances", "materials", "plugins", "quality", "user", "variants"]: diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index 80abd0c356..86bcc2719e 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -66,10 +66,11 @@ class PrintInformation(QObject): self._base_name = "" self._abbr_machine = "" self._job_name = "" + self._project_name = "" Application.getInstance().globalContainerStackChanged.connect(self._updateJobName) Application.getInstance().fileLoaded.connect(self.setBaseName) - + Application.getInstance().projectFileLoaded.connect(self.setProjectName) Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged) self._active_material_container = None @@ -78,7 +79,6 @@ class PrintInformation(QObject): self._material_amounts = [] - # Crate cura message translations and using translation keys initialize empty time Duration object for total time # and time for each feature def initializeCuraMessagePrintTimeProperties(self): @@ -241,6 +241,11 @@ class PrintInformation(QObject): self._job_name = name self.jobNameChanged.emit() + @pyqtSlot(str) + def setProjectName(self, name): + self._project_name = name + self.setJobName(name) + jobNameChanged = pyqtSignal() @pyqtProperty(str, notify = jobNameChanged) @@ -248,6 +253,11 @@ class PrintInformation(QObject): return self._job_name def _updateJobName(self): + # if the project name is set, we use the project name as the job name, so the job name should not get updated + # if a model file is loaded after that. + if self._project_name != "": + return + if self._base_name == "": self._job_name = "" self.jobNameChanged.emit() diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 79e137e87f..5b1e084262 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -26,6 +26,7 @@ from configparser import ConfigParser import zipfile import io import configparser +import os i18n_catalog = i18nCatalog("cura") @@ -876,6 +877,11 @@ class ThreeMFWorkspaceReader(WorkspaceReader): nodes = self._3mf_mesh_reader.read(file_name) if nodes is None: nodes = [] + + base_file_name = os.path.basename(file_name) + if base_file_name.endswith(".curaproject.3mf"): + base_file_name = base_file_name[:base_file_name.rfind(".curaproject.3mf")] + Application.getInstance().projectFileLoaded.emit(base_file_name) return nodes ## HACK: Replaces the material container in the given stack with a newly created material container. diff --git a/resources/qml/OpenFilesIncludingProjectsDialog.qml b/resources/qml/OpenFilesIncludingProjectsDialog.qml index c8df7b69a2..af8fb9e05f 100644 --- a/resources/qml/OpenFilesIncludingProjectsDialog.qml +++ b/resources/qml/OpenFilesIncludingProjectsDialog.qml @@ -36,8 +36,6 @@ UM.Dialog var meshName = backgroundItem.getMeshName(projectFile.toString()); backgroundItem.hasMesh(decodeURIComponent(meshName)); - // always update the job name with the loaded project - PrintInformation.setBaseName(meshName); } function loadModelFiles(fileUrls) From b318dc70872cd5091cfed4ea4c40a68a896cd43c Mon Sep 17 00:00:00 2001 From: "A.Sasin" Date: Thu, 12 Oct 2017 08:57:26 +0200 Subject: [PATCH 06/19] Added notification icon in recomended mode. The notification icon is only active if one of custom settings is changed CURA-4333 --- cura/CuraApplication.py | 6 +++ cura/Settings/MachineManager.py | 36 ++++++++++++++ resources/qml/SidebarSimple.qml | 84 +++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index c2517093bb..1a10e45662 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -400,6 +400,8 @@ class CuraApplication(QtApplication): # ALWAYS ask whether to keep or discard the profile self.showDiscardOrKeepProfileChanges.emit() + sidebarSimpleDiscardOrKeepProfileChanges = pyqtSignal() + @pyqtSlot(str) def discardOrKeepProfileChangesClosed(self, option): if option == "discard": @@ -409,6 +411,10 @@ class CuraApplication(QtApplication): global_stack.getTop().clear() + #event handler for SidebarSimple, which will update sliders view visibility (like:sliders..) + if Preferences.getInstance().getValue("cura/active_mode") == 0: + self.sidebarSimpleDiscardOrKeepProfileChanges.emit() + @pyqtSlot(int) def messageBoxClosed(self, button): if self._message_box_callback: diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index e0e81fba1b..dc71fe9ca9 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -413,6 +413,42 @@ class MachineManager(QObject): return False + ## Check whether user containers have adjusted settings or not + # \param skip_keys \type{list} List of setting keys which will be not taken into account ("support_enable" , "infill_sparse_density"...) + # \return \type{boole} Return true if user containers have any of adjusted settings + @pyqtSlot("QVariantList", result = bool) + def hasUserCustomSettings(self, skip_keys = []) -> bool: + + user_setting_keys = [] + try: + if not self._global_container_stack: + return False + + allContainers = self._global_container_stack.getContainers() + + for container in allContainers: + meta = container.getMetaData() + if meta and meta["type"] and meta["type"] == "user": + user_setting_keys.extend(container.getAllKeys()) + + stacks = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())) + for stack in stacks: + + for container in stack.getContainers(): + meta = container.getMetaData() + if meta and meta["type"] and meta["type"] == "user": + user_setting_keys.extend(container.getAllKeys()) + + for skip_key in skip_keys: + if skip_key in user_setting_keys: + user_setting_keys.remove(skip_key) + + except: + Logger.log("e", "While checking user custom settings occured error. skip_keys: %s", skip_keys ) + return False + + return len(user_setting_keys) > 0 + @pyqtProperty(int, notify = activeStackValueChanged) def numUserSettings(self) -> int: if not self._global_container_stack: diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index ea9ee507ba..3301d4af67 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -20,11 +20,40 @@ Item property variant minimumPrintTime: PrintInformation.minimumPrintTime; property variant maximumPrintTime: PrintInformation.maximumPrintTime; property bool settingsEnabled: ExtruderManager.activeExtruderStackId || machineExtruderCount.properties.value == 1 + property bool hasUserSettings; Component.onCompleted: PrintInformation.enabled = true Component.onDestruction: PrintInformation.enabled = false UM.I18nCatalog { id: catalog; name: "cura" } + onVisibleChanged: + { + if (visible) + { + base.checkUserSettings() + } + } + + Connections + { + target: CuraApplication + onSidebarSimpleDiscardOrKeepProfileChanges: + { + base.hasUserSettings = false + } + } + + function checkUserSettings(){ + + var skip_keys = ["support_enable" , + "infill_sparse_density", + "gradual_infill_steps", + "adhesion_type", + "support_extruder_nr"] + + base.hasUserSettings = Cura.MachineManager.hasUserCustomSettings(skip_keys) + } + ScrollView { visible: Cura.MachineManager.activeMachineName != "" // If no printers added then the view is invisible @@ -291,6 +320,7 @@ Item implicitWidth: 10 * screenScaleFactor implicitHeight: implicitWidth radius: implicitWidth / 2 + visible: !hasUserSettings; } } } @@ -308,6 +338,33 @@ Item } } } + + + //If any of settings were changed in custom mode then the Rectangle will + //overlap quality slider area. It is used to catch mouse click + Rectangle { + anchors.verticalCenter: parent.verticalCenter + anchors.right: extrudersModelCheckBox.right + anchors.rightMargin: UM.Theme.getSize("default_margin").width + width: qualitySlider.width + height: qualitySlider.height * 1.5 + //border.width: UM.Theme.getSize("default_lining").width // dispay overlap zone + //border.color: UM.Theme.getColor("lining") + + color: "transparent" + + visible: hasUserSettings + enabled: hasUserSettings + + + MouseArea { + anchors.fill: parent + onClicked: { + discardOrKeepProfileChangesDialog.show() + } + } + + } } Label @@ -343,6 +400,33 @@ Item color: (qualityModel.availableTotalTicks > 0) ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") horizontalAlignment: Text.AlignRight } + + UM.SimpleButton + { + id: customisedSettings + + visible: hasUserSettings + height: speedSlider.height * 0.8 + width: speedSlider.height * 0.8 + + anchors.verticalCenter: speedSlider.verticalCenter + anchors.right: speedSlider.left + anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width / 2 + + color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button"); + iconSource: UM.Theme.getIcon("reset"); + + onClicked: + { + discardOrKeepProfileChangesDialog.show() + } + onEntered: + { + var content = catalog.i18nc("@tooltip","You have selected a custom profile. If you want to change it, go to custom mode.") + base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("sidebar_margin").width, customisedSettings.height), content) + } + onExited: base.hideTooltip() + } } From f94954e9ca8425764b032cd70f4c10a9ac484945 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 12 Oct 2017 09:28:50 +0200 Subject: [PATCH 07/19] Improved end g-code This one removes the hair at the end of this print a bit better. Contributes to issue EM-1859. --- resources/definitions/ultimaker3.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/ultimaker3.def.json b/resources/definitions/ultimaker3.def.json index 2f4ad4e1a8..21f80e18fd 100644 --- a/resources/definitions/ultimaker3.def.json +++ b/resources/definitions/ultimaker3.def.json @@ -67,7 +67,7 @@ "machine_extruder_count": { "default_value": 2 }, "extruder_prime_pos_abs": { "default_value": true }, "machine_start_gcode": { "default_value": "" }, - "machine_end_gcode": { "default_value": "G91 ;Relative movement\nG0 F2400 Z3 E-{retraction_amount}\nG90 ;Disable relative movement" }, + "machine_end_gcode": { "default_value": "G91 ;Relative movement\nG0 F15000 X8.0 Z0.5 E-4.5 ;Wiping+material retraction\nG0 F10000 Z1.5 E4.5 ;Compensation for the retraction\nG90 ;Disable relative movement" }, "prime_tower_position_x": { "value": "machine_depth - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) - 30" }, "prime_tower_wipe_enabled": { "default_value": false }, From ca28748bc32d04495f93aec00b9cce70a93e6eb2 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 12 Oct 2017 10:26:38 +0200 Subject: [PATCH 08/19] Add missing translations from broken string freeze These texts were added later after the strings were frozen. Bad! But this is the German translation for it, retrieved from a secondary speaker here at the office. Contributes to issue CURA-4341. --- resources/i18n/de_DE/cura.po | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/resources/i18n/de_DE/cura.po b/resources/i18n/de_DE/cura.po index 1323070dbe..a18361802b 100644 --- a/resources/i18n/de_DE/cura.po +++ b/resources/i18n/de_DE/cura.po @@ -36,6 +36,31 @@ msgctxt "@label:status" msgid "Can't start print" msgstr "Druck startet nicht" +#: Manually added for plugins/UM3NetworkPrinting/DiscoverUM3Action.qml +msgctxt "@label" +msgid "This printer is not set up to host a group of Ultimaker 3 printers." +msgstr "Dieser Drucker ist nicht eingerichtet um eine Gruppe von Ultimaker 3 Druckern anzusteuern." + +#: Manually added for plugins/UM3NetworkPrinting/PrinterInfoBlock.qml +msgctxt "@label" +msgid "Finishes at: " +msgstr "Endet um: " + +#: Manually added for plugins/UM3NetworkPrinting/DiscoverUM3Action.qml +msgctxt "@label" +msgid "This printer is the host for a group of %1 Ultimaker 3 printers." +msgstr "Dieser Drucker steuert eine Gruppe von %1 Ultimaker 3 Druckern an." + +#: Manually added for plugins/UM3NetworkPrinting/NetworkClusterPrinterOutputDevice.py +msgctxt "@info:status" +msgid "Printer '{printer_name}' has finished printing '{job_name}'." +msgstr "Drucker '{printer_name}' hat '{job_name}' vollständig gedrückt." + +#: Manually added for plugins/UM3NetworkPrinting/NetworkClusterPrinterOutputDevice.py +msgctxt "@info:status" +msgid "Print finished" +msgstr "Druck vollendet" + #: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29 msgctxt "@action" msgid "Machine Settings" From af3c34b6fdd8f0e593f755139964dbddfea0502a Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Thu, 12 Oct 2017 10:46:25 +0200 Subject: [PATCH 09/19] Don't let the user select unreachable printers in the Cura Connect monitor tab CL-584 --- plugins/UM3NetworkPrinting/PrinterInfoBlock.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml b/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml index 005d719266..ab944d0dcc 100644 --- a/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml +++ b/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml @@ -73,7 +73,7 @@ Rectangle hoverEnabled: true; // Only clickable if no printer is selected - enabled: OutputDevice.selectedPrinterName == "" + enabled: OutputDevice.selectedPrinterName == "" && printer.status !== "unreachable" } Row From a3b8642a4e30f6192647b94d724473a4e5e1880b Mon Sep 17 00:00:00 2001 From: "A.Sasin" Date: Thu, 12 Oct 2017 11:45:25 +0200 Subject: [PATCH 10/19] Added text.elideRight on SidebarSimple --- resources/qml/SidebarSimple.qml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index 59972bbf99..920044e277 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -661,11 +661,14 @@ Item anchors.topMargin: Math.floor(UM.Theme.getSize("sidebar_margin").height * 1.5) anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width + anchors.right: infillCellLeft.right + anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width anchors.verticalCenter: enableSupportCheckBox.verticalCenter text: catalog.i18nc("@label", "Generate Support"); font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); + elide: Text.ElideRight } CheckBox @@ -711,10 +714,13 @@ Item visible: supportExtruderCombobox.visible anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width + anchors.right: infillCellLeft.right + anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width anchors.verticalCenter: supportExtruderCombobox.verticalCenter text: catalog.i18nc("@label", "Support Extruder"); font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); + elide: Text.ElideRight } ComboBox From 8d20f62dc9fc334e313fd39a18c88f838a030220 Mon Sep 17 00:00:00 2001 From: "A.Sasin" Date: Thu, 12 Oct 2017 11:57:02 +0200 Subject: [PATCH 11/19] Changed back to previous commit --- resources/qml/Preferences/MaterialView.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/MaterialView.qml index 597dcf7600..143f29c86e 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/MaterialView.qml @@ -16,8 +16,8 @@ TabView property bool editingEnabled: false; property string currency: UM.Preferences.getValue("cura/currency") ? UM.Preferences.getValue("cura/currency") : "€" - property real firstColumnWidth: (width * 0.45) | 0 - property real secondColumnWidth: (width * 0.45) | 0 + property real firstColumnWidth: (width * 0.50) | 0 + property real secondColumnWidth: (width * 0.40) | 0 property string containerId: "" property var materialPreferenceValues: UM.Preferences.getValue("cura/material_settings") ? JSON.parse(UM.Preferences.getValue("cura/material_settings")) : {} From 427afdbe23c45604ecc28c2fe287e18733d7b4be Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Thu, 12 Oct 2017 12:41:21 +0200 Subject: [PATCH 12/19] Correctly set up the cluster output device instances with the cluster size This fixes the Cura Connect messages shown in the network printer selection dialog. CL-555 --- .../NetworkPrinterOutputDevicePlugin.py | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/plugins/UM3NetworkPrinting/NetworkPrinterOutputDevicePlugin.py b/plugins/UM3NetworkPrinting/NetworkPrinterOutputDevicePlugin.py index ab9fbc64a8..24d65b47a8 100644 --- a/plugins/UM3NetworkPrinting/NetworkPrinterOutputDevicePlugin.py +++ b/plugins/UM3NetworkPrinting/NetworkPrinterOutputDevicePlugin.py @@ -153,7 +153,18 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin): if status_code == 200: # We know it's a cluster printer Logger.log("d", "Cluster printer detected: [%s]", reply.url()) + + try: + cluster_printers_list = json.loads(bytes(reply.readAll()).decode("utf-8")) + except json.JSONDecodeError: + Logger.log("e", "Printer returned invalid JSON.") + return + except UnicodeDecodeError: + Logger.log("e", "Printer returned incorrect UTF-8.") + return + self._network_requests_buffer[address]["cluster"] = True + self._network_requests_buffer[address]["cluster_size"] = len(cluster_printers_list) else: Logger.log("d", "This url is not from a cluster printer: [%s]", reply.url()) self._network_requests_buffer[address]["cluster"] = False @@ -165,7 +176,6 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin): instance_name = "manual:%s" % address system_info = self._network_requests_buffer[address]["system"] - is_cluster = self._network_requests_buffer[address]["cluster"] machine = "unknown" if "variant" in system_info: variant = system_info["variant"] @@ -181,10 +191,14 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin): b"manual": b"true", b"machine": machine.encode("utf-8") } + + if self._network_requests_buffer[address]["cluster"]: + properties[b"cluster_size"] = self._network_requests_buffer[address]["cluster_size"] + if instance_name in self._printers: # Only replace the printer if it is still in the list of (manual) printers self.removePrinter(instance_name) - self.addPrinter(instance_name, address, properties, force_cluster=is_cluster) + self.addPrinter(instance_name, address, properties) del self._network_requests_buffer[address] @@ -215,9 +229,9 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin): self._printers[key].connectionStateChanged.disconnect(self._onPrinterConnectionStateChanged) ## Because the model needs to be created in the same thread as the QMLEngine, we use a signal. - def addPrinter(self, name, address, properties, force_cluster=False): + def addPrinter(self, name, address, properties): cluster_size = int(properties.get(b"cluster_size", -1)) - if force_cluster or cluster_size >= 0: + if cluster_size >= 0: printer = NetworkClusterPrinterOutputDevice.NetworkClusterPrinterOutputDevice( name, address, properties, self._api_prefix) else: From 624aca324e8aab29d4eea1404b6899e2ea4b594c Mon Sep 17 00:00:00 2001 From: "A.Sasin" Date: Thu, 12 Oct 2017 13:42:21 +0200 Subject: [PATCH 13/19] Updated changelog, except Cross infill CURA-4391 --- plugins/ChangeLogPlugin/ChangeLog.txt | 76 ++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/plugins/ChangeLogPlugin/ChangeLog.txt b/plugins/ChangeLogPlugin/ChangeLog.txt index 57e6e05d9c..6ee523d35a 100755 --- a/plugins/ChangeLogPlugin/ChangeLog.txt +++ b/plugins/ChangeLogPlugin/ChangeLog.txt @@ -1,5 +1,79 @@ [3.0.0] -*Will be updated soon! +*Faster start-up +Start-up speed has been cut in half compared to the previous version. + +*New color scheme +Color scheme has been updated to reflect Ultimaker Cura rebrand. + +*Updated UX design +The Ultimaker Cura logo has moved from the bottom to the top of the interface. Print status icons have been updated and repositioned. + +*Redesigned splash screen +A new splash screen on Ultimaker Cura startup has been added. + +*Top navigation bar improvements +The width of tab functionality changes accordingly to the word space (multilingual). + +*Print quality slider +A slider can now be used to control the quality profile in recommended mode. + +*Infill slider +Model infill can now be changed using a slider in recommended mode. + +*Changed layer view +Layer view icon, panel and slider have moved to top-right of interface. + +*Rasterized build plate +The build plate now shows graduations of 10 mm and 1 mm for easy model positioning. + +*Changed row of extruder buttons +Extruder tabs have become buttons and icons have been updated. + +*Add an "Export to Cura" button in SOLIDWORKS +SOLIDWORKS plugin can now be installed using an automatic installer. + +*Siemens NX macro +When a user updates models in Siemens NX and clicks the button, the updated models replace the models opened in Ultimaker Cura. + +*Skin removal width +Remove thin strips of skin from a model to prevent print head zigzagging, in turn preventing vibrations. + +*Skin expand distance +Cutting away skins on steep overhangs makes prints less sturdy. By expanding skins with the thickness of walls, features will be better supported. In addition, features such as towers on top of infill will be stronger. + +*Extra skin wall count +Printing extra skin directly on top of infill can lead to gaps, curling and pillowing. This is reduced by printing a wall around the skin first, and also improves the printing speed. + +*Minimum extrusion for skin +Will prevent filling small gaps that are probably filled already, resulting in less strings, better top details and faster prints. + +*PVA retractions +PVA (switch) retraction length is increased, minimum travel distance for retraction is decreased and max count is slightly increased, this reduces stringing by a lot at the cost of slightly increased print time. + +*Z seam options +Gives the user control over where to place the seam - hide it in convex corners or in easy to remove locations such as concave corners. Don’t let corner angles influence the seam position. + +*Quarter cubic infill +Similar to tetrahedral (octet) infill, but half of the lines are shifted half of the period up. This pattern sacrifices some rigidity of octet infill for greater toughness. + +*Layer start negative position +Layer start X/Y values can be less than 0 when the machine centre is zero. + +*PostProcessing stretch script +This new script performs "post stretch" algorithm to fix the problem of insufficient inner and outer diameters. Thanks to electrocbd for contributing. + +*Ironing speed settings +Ironing speed settings have been moved to experimental category. + +*Doodle3D plugin +Update Doodle3D plugin to connect with printers. Thanks to mith for contributing. + +*Bug fixes +- Customized profiles are not sent when connecting to a printer +- Sync z-hop with layer changes, thanks to smartavionics for contributing +- Memory leaks on MacOS +- Printer name not loaded when project file is opened +- Doodle3D Wifi box was selected by default on non-UM3 printers [2.7.0] *Top surface skin From eef4d61402bdcedc283a0967ceea4ece82b342b3 Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Thu, 12 Oct 2017 13:44:03 +0200 Subject: [PATCH 14/19] Correct the status message when a printer needs a config change but is unreachable CL-508 --- plugins/UM3NetworkPrinting/PrinterInfoBlock.qml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml b/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml index ab944d0dcc..1ced5e8233 100644 --- a/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml +++ b/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml @@ -257,6 +257,11 @@ Rectangle return catalog.i18nc("@label:status", "Disabled"); } + if (printer.status === "unreachable") + { + return printerStatusText(printer); + } + if (printJob != null) { switch (printJob.status) @@ -327,6 +332,12 @@ Rectangle { return "blocked-icon.svg"; } + + if (printer.status === "unreachable") + { + return ""; + } + if (printJob != null) { if(printJob.status === "queued") @@ -378,6 +389,11 @@ Rectangle return catalog.i18nc("@label", "Not accepting print jobs"); } + if (printer.status === "unreachable") + { + return ""; + } + if(printJob != null) { switch (printJob.status) From 8ed7918b6030b112e74ebdf4ffebed8c1299d6d4 Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Thu, 12 Oct 2017 14:02:19 +0200 Subject: [PATCH 15/19] Update the icon used to show that a printer is blocked. This applies to the printer status icons shown in the monitor tab when connected via Cura Connect. --- plugins/UM3NetworkPrinting/blocked-icon.svg | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/UM3NetworkPrinting/blocked-icon.svg b/plugins/UM3NetworkPrinting/blocked-icon.svg index 03bbe24e16..eba3efdab9 100644 --- a/plugins/UM3NetworkPrinting/blocked-icon.svg +++ b/plugins/UM3NetworkPrinting/blocked-icon.svg @@ -1,3 +1,6 @@ - - + + + + + From 920c90010fdd331187aa15488a5982330f72611a Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 12 Oct 2017 14:54:01 +0200 Subject: [PATCH 16/19] Fix base.selectedPrinter is undefined problem --- plugins/UM3NetworkPrinting/DiscoverUM3Action.qml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml index 205dbdc9d9..b20d17a6d4 100644 --- a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml +++ b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml @@ -278,6 +278,10 @@ Cura.MachineAction width: parent.width wrapMode: Text.WordWrap text:{ + if (base.selectedPrinter == undefined) + { + return ""; + } // The property cluster size does not exist for older UM3 devices. if(base.selectedPrinter != undefined && base.selectedPrinter.clusterSize == null || base.selectedPrinter.clusterSize == 1) { From cfcb47234ce41e3058a20dd08f4886666386de96 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 12 Oct 2017 17:10:04 +0200 Subject: [PATCH 17/19] Add cross infill to the change log Contributes to issue CURA-4391 and CURA-4095. --- plugins/ChangeLogPlugin/ChangeLog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/ChangeLogPlugin/ChangeLog.txt b/plugins/ChangeLogPlugin/ChangeLog.txt index 6ee523d35a..25880a66e4 100755 --- a/plugins/ChangeLogPlugin/ChangeLog.txt +++ b/plugins/ChangeLogPlugin/ChangeLog.txt @@ -56,6 +56,9 @@ Gives the user control over where to place the seam - hide it in convex corners *Quarter cubic infill Similar to tetrahedral (octet) infill, but half of the lines are shifted half of the period up. This pattern sacrifices some rigidity of octet infill for greater toughness. +*Cross infill +A fractal pattern infill that requires fewer retractions than other infill types. This is useful for flexible materials as it causes less material elongation. The internal structure given by this infill also assists flexible models having more resistance, while retaining ‘soft’ properties in all directions. + *Layer start negative position Layer start X/Y values can be less than 0 when the machine centre is zero. From 3ea9c3856c20d15d644233b704d5911823454ded Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 13 Oct 2017 13:06:48 +0200 Subject: [PATCH 18/19] CURA-4450 Updating UI after removing printer When removing a printer, the new one was activated but not signals were emitted so the UI didn't update correctly. Now the printer is added and signals are emitted. --- cura/Settings/MachineManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index e0e81fba1b..937d59fa07 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1096,7 +1096,7 @@ class MachineManager(QObject): machine_stacks = ContainerRegistry.getInstance().findContainerStacks(type = "machine") other_machine_stacks = [s for s in machine_stacks if s.getId() != machine_id] if other_machine_stacks: - Application.getInstance().setGlobalContainerStack(other_machine_stacks[0]) + self.setActiveMachine(other_machine_stacks[0].getId()) ExtruderManager.getInstance().removeMachineExtruders(machine_id) containers = ContainerRegistry.getInstance().findInstanceContainers(type = "user", machine = machine_id) From 73f6427a888ad94c93f94b2d385b58e115e01dfc Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 13 Oct 2017 16:21:23 +0200 Subject: [PATCH 19/19] Change mainwindow name to Ultimaker Cura --- resources/qml/Cura.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index ca32a6eaab..cb0211f29f 100755 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -16,7 +16,7 @@ UM.MainWindow { id: base //: Cura application window title - title: catalog.i18nc("@title:window","Cura"); + title: catalog.i18nc("@title:window","Ultimaker Cura"); viewportRect: Qt.rect(0, 0, (base.width - sidebar.width) / base.width, 1.0) property bool showPrintMonitor: false