Browse Source

WIP: Make MachineSetting panel work

Lipu Fei 6 years ago
parent
commit
987ebba33b

+ 7 - 1
cura/CuraApplication.py

@@ -60,6 +60,7 @@ from cura.Scene.CuraSceneNode import CuraSceneNode
 from cura.Scene.CuraSceneController import CuraSceneController
 
 from cura.UI.WelcomePagesModel import WelcomePagesModel
+from cura.UI.MachineSettingsManager import MachineSettingsManager
 
 from UM.Settings.SettingDefinition import SettingDefinition, DefinitionPropertyType
 from UM.Settings.ContainerRegistry import ContainerRegistry
@@ -212,8 +213,9 @@ class CuraApplication(QtApplication):
         self._cura_scene_controller = None
         self._machine_error_checker = None
 
-        self._discovered_printer_model = DiscoveredPrintersModel(self)
+        self._machine_settings_manager = MachineSettingsManager(self)
 
+        self._discovered_printer_model = DiscoveredPrintersModel(self)
         self._welcome_pages_model = WelcomePagesModel(self)
 
         self._quality_profile_drop_down_menu_model = None
@@ -862,6 +864,10 @@ class CuraApplication(QtApplication):
     def getWelcomePagesModel(self, *args) -> "WelcomePagesModel":
         return self._welcome_pages_model
 
+    @pyqtSlot(result = QObject)
+    def getMachineSettingsManager(self, *args) -> "MachineSettingsManager":
+        return self._machine_settings_manager
+
     def getCuraFormulaFunctions(self, *args) -> "CuraFormulaFunctions":
         if self._cura_formula_functions is None:
             self._cura_formula_functions = CuraFormulaFunctions(self)

+ 66 - 0
cura/UI/MachineSettingsManager.py

@@ -0,0 +1,66 @@
+
+from typing import Any, Dict, Optional, TYPE_CHECKING
+
+from PyQt5.QtCore import Qt, QObject, pyqtSlot
+
+from UM.i18n import i18nCatalog
+
+
+class MachineSettingsManager(QObject):
+
+    def __init__(self, parent: Optional["QObject"] = None) -> None:
+        super().__init__(parent)
+        self._i18n_catalog = i18nCatalog("cura")
+
+        from cura.CuraApplication import CuraApplication
+        self._application = CuraApplication.getInstance()
+
+    # Force rebuilding the build volume by reloading the global container stack. This is a bit of a hack, but it seems
+    # quite enough.
+    @pyqtSlot()
+    def forceUpdate(self) -> None:
+        self._application.getMachineManager().globalContainerChanged.emit()
+
+    # Function for the Machine Settings panel (QML) to update the compatible material diameter after a user has changed
+    # an extruder's compatible material diameter. This ensures that after the modification, changes can be notified
+    # and updated right away.
+    @pyqtSlot(int)
+    def updateMaterialForDiameter(self, extruder_position: int):
+        # Updates the material container to a material that matches the material diameter set for the printer
+        self._application.getMachineManager().updateMaterialWithVariant(str(extruder_position))
+
+    # FIXME(Lipu): Better document what this function does, especially the fuzzy gcode flavor and has_materials logic
+    #              regarding UM2 and UM2+
+    # Function for the Machine Settings panel (QML) to update after the usre changes "Number of Extruders".
+    @pyqtSlot()
+    def updateHasMaterialsMetadata(self):
+        machine_manager = self._application.getMachineManager()
+        material_manager = self._application.getMaterialManager()
+
+        global_stack = material_manager.activeMachine
+
+        definition = global_stack.definition
+        if definition.getProperty("machine_gcode_flavor", "value") != "UltiGCode" or definition.getMetaDataEntry(
+                "has_materials", False):
+            # In other words: only continue for the UM2 (extended), but not for the UM2+
+            return
+
+        extruder_positions = list(global_stack.extruders.keys())
+        has_materials = global_stack.getProperty("machine_gcode_flavor", "value") != "UltiGCode"
+
+        material_node = None
+        if has_materials:
+            global_stack.setMetaDataEntry("has_materials", True)
+        else:
+            # The metadata entry is stored in an ini, and ini files are parsed as strings only.
+            # Because any non-empty string evaluates to a boolean True, we have to remove the entry to make it False.
+            if "has_materials" in global_stack.getMetaData():
+                global_stack.removeMetaDataEntry("has_materials")
+
+        # set materials
+        for position in extruder_positions:
+            if has_materials:
+                material_node = material_manager.getDefaultMaterial(global_stack, position, None)
+            machine_manager.setMaterial(position, material_node)
+
+        self.forceUpdate()

+ 16 - 5
resources/qml/MachineSettings/ComboBoxWithOptions.qml

@@ -39,8 +39,8 @@ UM.TooltipArea
     property string tooltipText: propertyProvider.properties.description
 
     // callback functions
-    property var afterOnActivateFunction: dummy_func
     property var forceUpdateOnChangeFunction: dummy_func
+    property var afterOnEditingFinishedFunction: dummy_func
 
     // a dummy function for default property values
     function dummy_func() {}
@@ -64,8 +64,10 @@ UM.TooltipArea
     ListModel
     {
         id: defaultOptionsModel
-        Component.onCompleted:
+
+        function updateModel()
         {
+            clear()
             // Options come in as a string-representation of an OrderedDict
             var options = propertyProvider.properties.options.match(/^OrderedDict\(\[\((.*)\)\]\)$/)
             if (options)
@@ -74,10 +76,19 @@ UM.TooltipArea
                 for (var i = 0; i < options.length; i++)
                 {
                     var option = options[i].substring(1, options[i].length - 1).split("', '")
-                    defaultOptionsModel.append({text: option[1], value: option[0]})
+                    append({text: option[1], value: option[0]})
                 }
             }
         }
+
+        Component.onCompleted: updateModel()
+    }
+
+    // Remake the model when the model is bound to a different container stack
+    Connections
+    {
+        target: propertyProvider
+        onContainerStackChanged: defaultOptionsModel.updateModel()
     }
 
     CuraComboBox
@@ -107,11 +118,11 @@ UM.TooltipArea
 
         onActivated:
         {
-            if(propertyProvider.properties.value != model.get(index).value)
+            if (propertyProvider.properties.value != model.get(index).value)
             {
                 propertyProvider.setPropertyValue("value", model.get(index).value)
                 forceUpdateOnChangeFunction()
-                afterOnActivateFunction()
+                afterOnEditingFinishedFunction()
             }
         }
     }

+ 1 - 1
resources/qml/MachineSettings/NumericTextFieldWithUnit.qml

@@ -181,7 +181,7 @@ UM.TooltipArea
                     propertyProvider.setPropertyValue("value", text)
                 }
                 forceUpdateOnChangeFunction()
-                afterOnEditingFinished()
+                afterOnEditingFinishedFunction()
             }
         }
 

+ 16 - 7
resources/qml/WelcomePages/MachineSettingsExtruderTab.qml

@@ -23,8 +23,6 @@ Item
     anchors.right: parent.right
     anchors.top: parent.top
 
-    property string extruderStackId: ""
-
     property int labelWidth: 180
     property int controlWidth: UM.Theme.getSize("setting_control").width * 3 / 4
     property var labelFont: UM.Theme.getFont("medium")
@@ -33,6 +31,15 @@ Item
     property int columnSpacing: 3
     property int propertyStoreIndex: 5  // definition_changes
 
+    property string extruderStackId: ""
+    property int extruderPosition: 0
+    property var forceUpdateFunction: CuraApplication.getMachineSettingsManager().forceUpdate
+
+    function updateMaterialDiameter()
+    {
+        CuraApplication.getMachineSettingsManager().updateMaterialForDiameter(extruderPosition)
+    }
+
     Item
     {
         id: upperBlock
@@ -73,7 +80,7 @@ Item
                 labelWidth: base.labelWidth
                 controlWidth: base.controlWidth
                 unitText: catalog.i18nc("@label", "mm")
-                // TODO: add forceUpdateOnChangeFunction:
+                forceUpdateOnChangeFunction: forceUpdateFunction
             }
 
             NumericTextFieldWithUnit  // "Compatible material diameter"
@@ -87,7 +94,9 @@ Item
                 labelWidth: base.labelWidth
                 controlWidth: base.controlWidth
                 unitText: catalog.i18nc("@label", "mm")
-                // TODO: add forceUpdateOnChangeFunction:
+                forceUpdateOnChangeFunction: forceUpdateFunction
+                // Other modules won't automatically respond after the user changes the value, so we need to force it.
+                afterOnEditingFinishedFunction: updateMaterialDiameter
             }
 
             NumericTextFieldWithUnit  // "Nozzle offset X"
@@ -101,7 +110,7 @@ Item
                 labelWidth: base.labelWidth
                 controlWidth: base.controlWidth
                 unitText: catalog.i18nc("@label", "mm")
-                // TODO: add forceUpdateOnChangeFunction:
+                forceUpdateOnChangeFunction: forceUpdateFunction
             }
 
             NumericTextFieldWithUnit  // "Nozzle offset Y"
@@ -115,7 +124,7 @@ Item
                 labelWidth: base.labelWidth
                 controlWidth: base.controlWidth
                 unitText: catalog.i18nc("@label", "mm")
-                // TODO: add forceUpdateOnChangeFunction:
+                forceUpdateOnChangeFunction: forceUpdateFunction
             }
 
             NumericTextFieldWithUnit  // "Cooling Fan Number"
@@ -129,7 +138,7 @@ Item
                 labelWidth: base.labelWidth
                 controlWidth: base.controlWidth
                 unitText: ""
-                // TODO: add forceUpdateOnChangeFunction:
+                forceUpdateOnChangeFunction: forceUpdateFunction
             }
         }
     }

+ 37 - 27
resources/qml/WelcomePages/MachineSettingsPrinterTab.qml

@@ -30,6 +30,10 @@ Item
     property int columnSpacing: 3
     property int propertyStoreIndex: 5  // definition_changes
 
+    property string machineStackId: Cura.MachineManager.activeMachineId
+
+    property var forceUpdateFunction: CuraApplication.getMachineSettingsManager().forceUpdate
+
     Item
     {
         id: upperBlock
@@ -61,7 +65,7 @@ Item
             NumericTextFieldWithUnit  // "X (Width)"
             {
                 id: machineXWidthField
-                containerStackId: Cura.MachineManager.activeMachineId
+                containerStackId: machineStackId
                 settingKey: "machine_width"
                 settingStoreIndex: propertyStoreIndex
                 labelText: catalog.i18nc("@label", "X (Width)")
@@ -69,13 +73,13 @@ Item
                 labelWidth: base.labelWidth
                 controlWidth: base.controlWidth
                 unitText: catalog.i18nc("@label", "mm")
-                // TODO: add forceUpdateOnChangeFunction:
+                forceUpdateOnChangeFunction: forceUpdateFunction
             }
 
             NumericTextFieldWithUnit  // "Y (Depth)"
             {
                 id: machineYDepthField
-                containerStackId: Cura.MachineManager.activeMachineId
+                containerStackId: machineStackId
                 settingKey: "machine_depth"
                 settingStoreIndex: propertyStoreIndex
                 labelText: catalog.i18nc("@label", "Y (Depth)")
@@ -83,13 +87,13 @@ Item
                 labelWidth: base.labelWidth
                 controlWidth: base.controlWidth
                 unitText: catalog.i18nc("@label", "mm")
-                // TODO: add forceUpdateOnChangeFunction:
+                forceUpdateOnChangeFunction: forceUpdateFunction
             }
 
             NumericTextFieldWithUnit  // "Z (Height)"
             {
                 id: machineZHeightField
-                containerStackId: Cura.MachineManager.activeMachineId
+                containerStackId: machineStackId
                 settingKey: "machine_height"
                 settingStoreIndex: propertyStoreIndex
                 labelText: catalog.i18nc("@label", "Z (Height)")
@@ -97,58 +101,61 @@ Item
                 labelWidth: base.labelWidth
                 controlWidth: base.controlWidth
                 unitText: catalog.i18nc("@label", "mm")
-                // TODO: add forceUpdateOnChangeFunction:
+                forceUpdateOnChangeFunction: forceUpdateFunction
             }
 
             ComboBoxWithOptions  // "Build plate shape"
             {
                 id: buildPlateShapeComboBox
-                containerStackId: Cura.MachineManager.activeMachineId
+                containerStackId: machineStackId
                 settingKey: "machine_shape"
                 settingStoreIndex: propertyStoreIndex
                 labelText: catalog.i18nc("@label", "Build plate shape")
                 labelFont: base.labelFont
                 labelWidth: base.labelWidth
                 controlWidth: base.controlWidth
-                // TODO: add forceUpdateOnChangeFunction:
+                forceUpdateOnChangeFunction: forceUpdateFunction
             }
 
             SimpleCheckBox  // "Origin at center"
             {
                 id: originAtCenterCheckBox
-                containerStackId: Cura.MachineManager.activeMachineId
+                containerStackId: machineStackId
                 settingKey: "machine_center_is_zero"
                 settingStoreIndex: propertyStoreIndex
                 labelText: catalog.i18nc("@label", "Origin at center")
                 labelFont: base.labelFont
                 labelWidth: base.labelWidth
-                // TODO: add forceUpdateOnChangeFunction:
+                forceUpdateOnChangeFunction: forceUpdateFunction
             }
 
             SimpleCheckBox  // "Heated bed"
             {
                 id: heatedBedCheckBox
-                containerStackId: Cura.MachineManager.activeMachineId
+                containerStackId: machineStackId
                 settingKey: "machine_heated_bed"
                 settingStoreIndex: propertyStoreIndex
                 labelText: catalog.i18nc("@label", "Heated bed")
                 labelFont: base.labelFont
                 labelWidth: base.labelWidth
-                // TODO: add forceUpdateOnChangeFunction:
+                forceUpdateOnChangeFunction: forceUpdateFunction
             }
 
             ComboBoxWithOptions  // "G-code flavor"
             {
                 id: gcodeFlavorComboBox
-                containerStackId: Cura.MachineManager.activeMachineId
+                containerStackId: machineStackId
                 settingKey: "machine_gcode_flavor"
                 settingStoreIndex: propertyStoreIndex
                 labelText: catalog.i18nc("@label", "G-code flavor")
                 labelFont: base.labelFont
                 labelWidth: base.labelWidth
                 controlWidth: base.controlWidth
-                // TODO: add forceUpdateOnChangeFunction:
-                // TODO: add afterOnActivate: manager.updateHasMaterialsMetadata
+                forceUpdateOnChangeFunction: forceUpdateFunction
+                // FIXME(Lipu): better document this.
+                // This has something to do with UM2 and UM2+ regarding "has_material" and the gcode flavor settings.
+                // I don't remember exactly what.
+                afterOnEditingFinishedFunction: CuraApplication.getMachineSettingsManager().updateHasMaterialsMetadata
             }
         }
 
@@ -185,7 +192,7 @@ Item
                 axisName: "x"
                 axisMinOrMax: "min"
 
-                // TODO: add forceUpdateOnChangeFunction:
+                forceUpdateOnChangeFunction: forceUpdateFunction
             }
 
             PrintHeadMinMaxTextField  // "Y min"
@@ -203,7 +210,7 @@ Item
                 axisName: "y"
                 axisMinOrMax: "min"
 
-                // TODO: add forceUpdateOnChangeFunction:
+                forceUpdateOnChangeFunction: forceUpdateFunction
             }
 
             PrintHeadMinMaxTextField  // "X max"
@@ -221,14 +228,14 @@ Item
                 axisName: "x"
                 axisMinOrMax: "max"
 
-                // TODO: add forceUpdateOnChangeFunction:
+                forceUpdateOnChangeFunction: forceUpdateFunction
             }
 
             PrintHeadMinMaxTextField  // "Y max"
             {
                 id: machineYMaxField
 
-                containerStackId: Cura.MachineManager.activeMachineId
+                containerStackId: machineStackId
                 settingKey: "machine_head_with_fans_polygon"
                 settingStoreIndex: propertyStoreIndex
 
@@ -241,13 +248,13 @@ Item
                 axisName: "y"
                 axisMinOrMax: "max"
 
-                // TODO: add forceUpdateOnChangeFunction:
+                forceUpdateOnChangeFunction: forceUpdateFunction
             }
 
             NumericTextFieldWithUnit  // "Gantry Height"
             {
                 id: machineGantryHeightField
-                containerStackId: Cura.MachineManager.activeMachineId
+                containerStackId: machineStackId
                 settingKey: "gantry_height"
                 settingStoreIndex: propertyStoreIndex
                 labelText: catalog.i18nc("@label", "Gantry Height")
@@ -255,21 +262,24 @@ Item
                 labelWidth: base.labelWidth
                 controlWidth: base.controlWidth
                 unitText: catalog.i18nc("@label", "mm")
-                // TODO: add forceUpdateOnChangeFunction:
+                forceUpdateOnChangeFunction: forceUpdateFunction
             }
 
             ComboBoxWithOptions  // "Number of Extruders"
             {
                 id: numberOfExtrudersComboBox
-                containerStackId: Cura.MachineManager.activeMachineId
+                containerStackId: machineStackId
                 settingKey: "machine_extruder_count"
                 settingStoreIndex: propertyStoreIndex
                 labelText: catalog.i18nc("@label", "Number of Extruders")
                 labelFont: base.labelFont
                 labelWidth: base.labelWidth
                 controlWidth: base.controlWidth
-                // TODO: add forceUpdateOnChangeFunction:
-                // TODO: add afterOnActivate: manager.updateHasMaterialsMetadata
+                forceUpdateOnChangeFunction: forceUpdateFunction
+                // FIXME(Lipu): better document this.
+                // This has something to do with UM2 and UM2+ regarding "has_material" and the gcode flavor settings.
+                // I don't remember exactly what.
+                afterOnEditingFinishedFunction: CuraApplication.getMachineSettingsManager().updateHasMaterialsMetadata
 
                 optionModel: ListModel
                 {
@@ -305,7 +315,7 @@ Item
             width: base.columnWidth - UM.Theme.getSize("default_margin").width
 
             labelText: catalog.i18nc("@title:label", "Start G-code")
-            containerStackId: Cura.MachineManager.activeMachineId
+            containerStackId: machineStackId
             settingKey: "machine_start_gcode"
             settingStoreIndex: propertyStoreIndex
         }
@@ -319,7 +329,7 @@ Item
             width: base.columnWidth - UM.Theme.getSize("default_margin").width
 
             labelText: catalog.i18nc("@title:label", "End G-code")
-            containerStackId: Cura.MachineManager.activeMachineId
+            containerStackId: machineStackId
             settingKey: "machine_end_gcode"
             settingStoreIndex: propertyStoreIndex
         }

+ 25 - 9
resources/qml/WelcomePages/TestContent.qml

@@ -26,11 +26,31 @@ Item
 
     property var extrudersModel: Cura.ExtrudersModel {}
 
-    onVisibleChanged:
+    // If we create a CuraTabButton for "Printer" and use Repeater for extruders, for some reason, once the component
+    // finishes it will automatically change "currentIndex = 1", and it is VERY difficult to change "currentIndex = 0"
+    // after that. Using a model and a Repeater to create both "Printer" and extruder CuraTabButtons seem to solve this
+    // problem.
+    Connections
     {
-        if (visible)
+        target: extrudersModel
+        onItemsChanged: tabNameModel.update()
+    }
+
+    ListModel
+    {
+        id: tabNameModel
+
+        Component.onCompleted: update()
+
+        function update()
         {
-            tabBar.currentIndex = 0
+            clear()
+            append({ name: catalog.i18nc("@title:tab", "Printer") })
+            for (var i = 0; i < extrudersModel.count; i++)
+            {
+                const m = extrudersModel.getItem(i)
+                append({ name: m.name })
+            }
         }
     }
 
@@ -46,14 +66,9 @@ Item
             id: tabBar
             width: parent.width
 
-            CuraTabButton
-            {
-                text: catalog.i18nc("@title:tab", "Printer")
-            }
-
             Repeater
             {
-                model: extrudersModel
+                model: tabNameModel
                 delegate: CuraTabButton
                 {
                     text: model.name
@@ -83,6 +98,7 @@ Item
                 delegate: MachineSettingsExtruderTab
                 {
                     id: discoverTab
+                    extruderPosition: model.index
                     extruderStackId: model.id
                 }
             }

+ 0 - 1
resources/qml/Widgets/CuraTabButton.qml

@@ -3,7 +3,6 @@
 
 import QtQuick 2.10
 import QtQuick.Controls 2.3
-import QtQuick.Layouts 1.3
 
 import UM 1.3 as UM
 import Cura 1.1 as Cura