Browse Source

WIP: MachineSettings Printer tab

Lipu Fei 6 years ago
parent
commit
449740a631

+ 4 - 0
cura/Settings/GlobalStack.py

@@ -64,6 +64,10 @@ class GlobalStack(CuraContainerStack):
         machine_extruder_count = self.getProperty("machine_extruder_count", "value")
         machine_extruder_count = self.getProperty("machine_extruder_count", "value")
         return result_list[:machine_extruder_count]
         return result_list[:machine_extruder_count]
 
 
+    @pyqtProperty(int, constant = True)
+    def maxExtruderCount(self):
+        return len(self.getMetaDataEntry("machine_extruder_trains"))
+
     @classmethod
     @classmethod
     def getLoadingPriority(cls) -> int:
     def getLoadingPriority(cls) -> int:
         return 2
         return 2

+ 46 - 47
resources/qml/MachineSettings/ComboBoxWithOptions.qml

@@ -34,6 +34,7 @@ UM.TooltipArea
     property alias labelText: fieldLabel.text
     property alias labelText: fieldLabel.text
     property alias labelFont: fieldLabel.font
     property alias labelFont: fieldLabel.font
     property alias labelWidth: fieldLabel.width
     property alias labelWidth: fieldLabel.width
+    property alias optionModel: comboBox.model
 
 
     property string tooltipText: propertyProvider.properties.description
     property string tooltipText: propertyProvider.properties.description
 
 
@@ -50,69 +51,67 @@ UM.TooltipArea
         watchedProperties: [ "value", "options", "description" ]
         watchedProperties: [ "value", "options", "description" ]
     }
     }
 
 
-    Row
+    Label
     {
     {
-        spacing: UM.Theme.getSize("default_margin").width
-
-        Label
-        {
-            id: fieldLabel
-            anchors.verticalCenter: comboBox.verticalCenter
-            visible: text != ""
-            font: UM.Theme.getFont("medium")
-            renderType: Text.NativeRendering
-        }
+        id: fieldLabel
+        anchors.left: parent.left
+        anchors.verticalCenter: comboBox.verticalCenter
+        visible: text != ""
+        font: UM.Theme.getFont("medium")
+        renderType: Text.NativeRendering
+    }
 
 
-        ListModel
+    ListModel
+    {
+        id: defaultOptionsModel
+        Component.onCompleted:
         {
         {
-            id: optionsModel
-            Component.onCompleted:
+            // Options come in as a string-representation of an OrderedDict
+            var options = propertyProvider.properties.options.match(/^OrderedDict\(\[\((.*)\)\]\)$/)
+            if (options)
             {
             {
-                // Options come in as a string-representation of an OrderedDict
-                var options = propertyProvider.properties.options.match(/^OrderedDict\(\[\((.*)\)\]\)$/)
-                if (options)
+                options = options[1].split("), (")
+                for (var i = 0; i < options.length; i++)
                 {
                 {
-                    options = options[1].split("), (")
-                    for (var i = 0; i < options.length; i++)
-                    {
-                        var option = options[i].substring(1, options[i].length - 1).split("', '")
-                        optionsModel.append({text: option[1], value: option[0]})
-                    }
+                    var option = options[i].substring(1, options[i].length - 1).split("', '")
+                    defaultOptionsModel.append({text: option[1], value: option[0]})
                 }
                 }
             }
             }
         }
         }
+    }
 
 
-        CuraComboBox
+    CuraComboBox
+    {
+        id: comboBox
+        anchors.left: fieldLabel.right
+        anchors.leftMargin: UM.Theme.getSize("default_margin").width
+        width: comboBoxWithOptions.controlWidth
+        height: comboBoxWithOptions.controlHeight
+        model: defaultOptionsModel
+        textRole: "text"
+
+        currentIndex:
         {
         {
-            id: comboBox
-            width: comboBoxWithOptions.controlWidth
-            height: comboBoxWithOptions.controlHeight
-            model: optionsModel
-            textRole: "text"
-
-            currentIndex:
+            var currentValue = propertyProvider.properties.value
+            var index = 0
+            for (var i = 0; i < model.count; i++)
             {
             {
-                var currentValue = propertyProvider.properties.value
-                var index = 0
-                for (var i = 0; i < model.count; i++)
+                if (model.get(i).value == currentValue)
                 {
                 {
-                    if (model.get(i).value == currentValue)
-                    {
-                        index = i
-                        break
-                    }
+                    index = i
+                    break
                 }
                 }
-                return index
             }
             }
+            return index
+        }
 
 
-            onActivated:
+        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()
-                }
+                propertyProvider.setPropertyValue("value", model.get(index).value)
+                forceUpdateOnChangeFunction()
+                afterOnActivateFunction()
             }
             }
         }
         }
     }
     }

+ 40 - 7
resources/qml/MachineSettings/GcodeTextArea.qml

@@ -14,12 +14,10 @@ import Cura 1.1 as Cura
 //
 //
 UM.TooltipArea
 UM.TooltipArea
 {
 {
-    id: gcodeTextArea
+    id: control
 
 
     UM.I18nCatalog { id: catalog; name: "cura"; }
     UM.I18nCatalog { id: catalog; name: "cura"; }
 
 
-    height: childrenRect.height
-    width: childrenRect.width
     text: tooltip
     text: tooltip
 
 
     property alias containerStackId: propertyProvider.containerStackId
     property alias containerStackId: propertyProvider.containerStackId
@@ -28,22 +26,57 @@ UM.TooltipArea
 
 
     property string tooltip: propertyProvider.properties.description
     property string tooltip: propertyProvider.properties.description
 
 
+    property alias labelText: titleLabel.text
+    property alias labelFont: titleLabel.font
+
     UM.SettingPropertyProvider
     UM.SettingPropertyProvider
     {
     {
         id: propertyProvider
         id: propertyProvider
         watchedProperties: [ "value", "description" ]
         watchedProperties: [ "value", "description" ]
     }
     }
 
 
-    // TODO: put label here
+    Label   // Title Label
+    {
+        id: titleLabel
+        anchors.top: parent.top
+        anchors.left: parent.left
+        font: UM.Theme.getFont("medium_bold")
+        renderType: Text.NativeRendering
+    }
 
 
     TextArea
     TextArea
     {
     {
-        id: gcodeArea
-        width: areaWidth
-        height: areaHeight
+        id: gcodeTextArea
+        anchors.top: titleLabel.bottom
+        anchors.topMargin: UM.Theme.getSize("default_margin").height
+        anchors.bottom: parent.bottom
+        anchors.left: parent.left
+        anchors.right: parent.right
+
+        hoverEnabled: true
+        selectByMouse: true
+
         font: UM.Theme.getFont("fixed")
         font: UM.Theme.getFont("fixed")
+        renderType: Text.NativeRendering
         text: (propertyProvider.properties.value) ? propertyProvider.properties.value : ""
         text: (propertyProvider.properties.value) ? propertyProvider.properties.value : ""
         wrapMode: TextEdit.NoWrap
         wrapMode: TextEdit.NoWrap
+
+        background: Rectangle
+        {
+            border.color:
+            {
+                if (!gcodeTextArea.enabled)
+                {
+                    return UM.Theme.getColor("setting_control_disabled_border")
+                }
+                if (gcodeTextArea.hovered || gcodeTextArea.activeFocus)
+                {
+                    return UM.Theme.getColor("setting_control_border_highlight")
+                }
+                return UM.Theme.getColor("setting_control_border")
+            }
+        }
+
         onActiveFocusChanged:
         onActiveFocusChanged:
         {
         {
             if (!activeFocus)
             if (!activeFocus)

+ 111 - 114
resources/qml/MachineSettings/NumericTextFieldWithUnit.qml

@@ -59,147 +59,144 @@ UM.TooltipArea
         watchedProperties: [ "value", "description" ]
         watchedProperties: [ "value", "description" ]
     }
     }
 
 
-    Row
+    Label
     {
     {
-        id: itemRow
-        spacing: UM.Theme.getSize("default_margin").width
+        id: fieldLabel
+        anchors.left: parent.left
+        anchors.verticalCenter: textFieldWithUnit.verticalCenter
+        visible: text != ""
+        font: UM.Theme.getFont("medium")
+        renderType: Text.NativeRendering
+    }
 
 
-        Label
-        {
-            id: fieldLabel
-            anchors.verticalCenter: textFieldWithUnit.verticalCenter
-            visible: text != ""
-            font: UM.Theme.getFont("medium")
-            renderType: Text.NativeRendering
-        }
+    TextField
+    {
+        id: textFieldWithUnit
+        anchors.left: fieldLabel.right
+        anchors.leftMargin: UM.Theme.getSize("default_margin").width
 
 
-        TextField
-        {
-            id: textFieldWithUnit
+        width: numericTextFieldWithUnit.controlWidth
+        height: numericTextFieldWithUnit.controlHeight
 
 
-            width: numericTextFieldWithUnit.controlWidth
-            height: numericTextFieldWithUnit.controlHeight
+        // Background is a rounded-cornered box with filled color as state indication (normal, warning, error, etc.)
+        background: Rectangle
+        {
+            anchors.fill: parent
+            anchors.margins: Math.round(UM.Theme.getSize("default_lining").width)
+            radius: UM.Theme.getSize("setting_control_radius").width
 
 
-            // Background is a rounded-cornered box with filled color as state indication (normal, warning, error, etc.)
-            background: Rectangle
+            border.color:
             {
             {
-                anchors.fill: parent
-                anchors.margins: Math.round(UM.Theme.getSize("default_lining").width)
-                radius: UM.Theme.getSize("setting_control_radius").width
-
-                border.color:
+                if (!textFieldWithUnit.enabled)
                 {
                 {
-                    if (!textFieldWithUnit.enabled)
-                    {
-                        return UM.Theme.getColor("setting_control_disabled_border")
-                    }
-                    switch (propertyProvider.properties.validationState)
-                    {
-                        case "ValidatorState.Exception":
-                        case "ValidatorState.MinimumError":
-                        case "ValidatorState.MaximumError":
-                            return UM.Theme.getColor("setting_validation_error")
-                        case "ValidatorState.MinimumWarning":
-                        case "ValidatorState.MaximumWarning":
-                            return UM.Theme.getColor("setting_validation_warning")
-                    }
-                    // Validation is OK.
-                    if (textFieldWithUnit.hovered || textFieldWithUnit.activeFocus)
-                    {
-                        return UM.Theme.getColor("setting_control_border_highlight")
-                    }
-                    return UM.Theme.getColor("setting_control_border")
+                    return UM.Theme.getColor("setting_control_disabled_border")
                 }
                 }
-
-                color:
+                switch (propertyProvider.properties.validationState)
+                {
+                    case "ValidatorState.Exception":
+                    case "ValidatorState.MinimumError":
+                    case "ValidatorState.MaximumError":
+                        return UM.Theme.getColor("setting_validation_error")
+                    case "ValidatorState.MinimumWarning":
+                    case "ValidatorState.MaximumWarning":
+                        return UM.Theme.getColor("setting_validation_warning")
+                }
+                // Validation is OK.
+                if (textFieldWithUnit.hovered || textFieldWithUnit.activeFocus)
                 {
                 {
-                    if (!textFieldWithUnit.enabled)
-                    {
-                        return UM.Theme.getColor("setting_control_disabled")
-                    }
-                    switch (propertyProvider.properties.validationState)
-                    {
-                        case "ValidatorState.Exception":
-                        case "ValidatorState.MinimumError":
-                        case "ValidatorState.MaximumError":
-                            return UM.Theme.getColor("setting_validation_error_background")
-                        case "ValidatorState.MinimumWarning":
-                        case "ValidatorState.MaximumWarning":
-                            return UM.Theme.getColor("setting_validation_warning_background")
-                        case "ValidatorState.Valid":
-                            return UM.Theme.getColor("setting_validation_ok")
-                        default:
-                            return UM.Theme.getColor("setting_control")
-                    }
+                    return UM.Theme.getColor("setting_control_border_highlight")
                 }
                 }
+                return UM.Theme.getColor("setting_control_border")
             }
             }
 
 
-            hoverEnabled: true
-            selectByMouse: true
-            font: UM.Theme.getFont("default")
-            renderType: Text.NativeRendering
-
-            // When the textbox gets focused by TAB, select all text
-            onActiveFocusChanged:
+            color:
             {
             {
-                if (activeFocus && (focusReason == Qt.TabFocusReason || focusReason == Qt.BacktabFocusReason))
+                if (!textFieldWithUnit.enabled)
+                {
+                    return UM.Theme.getColor("setting_control_disabled")
+                }
+                switch (propertyProvider.properties.validationState)
                 {
                 {
-                    selectAll()
+                    case "ValidatorState.Exception":
+                    case "ValidatorState.MinimumError":
+                    case "ValidatorState.MaximumError":
+                        return UM.Theme.getColor("setting_validation_error_background")
+                    case "ValidatorState.MinimumWarning":
+                    case "ValidatorState.MaximumWarning":
+                        return UM.Theme.getColor("setting_validation_warning_background")
+                    case "ValidatorState.Valid":
+                        return UM.Theme.getColor("setting_validation_ok")
+                    default:
+                        return UM.Theme.getColor("setting_control")
                 }
                 }
             }
             }
+        }
+
+        hoverEnabled: true
+        selectByMouse: true
+        font: UM.Theme.getFont("default")
+        renderType: Text.NativeRendering
 
 
-            text:
+        // When the textbox gets focused by TAB, select all text
+        onActiveFocusChanged:
+        {
+            if (activeFocus && (focusReason == Qt.TabFocusReason || focusReason == Qt.BacktabFocusReason))
             {
             {
-                const value = propertyProvider.properties.value
-                return value ? value : ""
+                selectAll()
             }
             }
-            validator: RegExpValidator { regExp: allowNegativeValue ? /-?[0-9\.,]{0,6}/ : /[0-9\.,]{0,6}/ }
+        }
 
 
-            onEditingFinished: editingFinishedFunction()
+        text:
+        {
+            const value = propertyProvider.properties.value
+            return value ? value : ""
+        }
+        validator: RegExpValidator { regExp: allowNegativeValue ? /-?[0-9\.,]{0,6}/ : /[0-9\.,]{0,6}/ }
+
+        onEditingFinished: editingFinishedFunction()
 
 
-            property var editingFinishedFunction: defaultEditingFinishedFunction
+        property var editingFinishedFunction: defaultEditingFinishedFunction
 
 
-            function defaultEditingFinishedFunction()
+        function defaultEditingFinishedFunction()
+        {
+            if (propertyProvider && text != propertyProvider.properties.value)
             {
             {
-                if (propertyProvider && text != propertyProvider.properties.value)
+                // For some properties like the extruder-compatible material diameter, they need to
+                // trigger many updates, such as the available materials, the current material may
+                // need to be switched, etc. Although setting the diameter can be done directly via
+                // the provider, all the updates that need to be triggered then need to depend on
+                // the metadata update, a signal that can be fired way too often. The update functions
+                // can have if-checks to filter out the irrelevant updates, but still it incurs unnecessary
+                // overhead.
+                // The ExtruderStack class has a dedicated function for this call "setCompatibleMaterialDiameter()",
+                // and it triggers the diameter update signals only when it is needed. Here it is optionally
+                // choose to use setCompatibleMaterialDiameter() or other more specific functions that
+                // are available.
+                if (setValueFunction !== null)
                 {
                 {
-                    // For some properties like the extruder-compatible material diameter, they need to
-                    // trigger many updates, such as the available materials, the current material may
-                    // need to be switched, etc. Although setting the diameter can be done directly via
-                    // the provider, all the updates that need to be triggered then need to depend on
-                    // the metadata update, a signal that can be fired way too often. The update functions
-                    // can have if-checks to filter out the irrelevant updates, but still it incurs unnecessary
-                    // overhead.
-                    // The ExtruderStack class has a dedicated function for this call "setCompatibleMaterialDiameter()",
-                    // and it triggers the diameter update signals only when it is needed. Here it is optionally
-                    // choose to use setCompatibleMaterialDiameter() or other more specific functions that
-                    // are available.
-                    if (setValueFunction !== null)
-                    {
-                        setValueFunction(text)
-                    }
-                    else
-                    {
-                        propertyProvider.setPropertyValue("value", text)
-                    }
-                    forceUpdateOnChangeFunction()
-                    afterOnEditingFinished()
+                    setValueFunction(text)
                 }
                 }
+                else
+                {
+                    propertyProvider.setPropertyValue("value", text)
+                }
+                forceUpdateOnChangeFunction()
+                afterOnEditingFinished()
             }
             }
+        }
 
 
-            Label
-            {
-                id: unitLabel
-                anchors.right: parent.right
-                anchors.rightMargin: Math.round(UM.Theme.getSize("setting_unit_margin").width)
-                anchors.verticalCenter: parent.verticalCenter
-                text: unitText
-                textFormat: Text.PlainText
-                verticalAlignment: Text.AlignVCenter
-                renderType: Text.NativeRendering
-                color: UM.Theme.getColor("setting_unit")
-                font: UM.Theme.getFont("default")
-            }
+        Label
+        {
+            id: unitLabel
+            anchors.right: parent.right
+            anchors.rightMargin: Math.round(UM.Theme.getSize("setting_unit_margin").width)
+            anchors.verticalCenter: parent.verticalCenter
+            text: unitText
+            textFormat: Text.PlainText
+            verticalAlignment: Text.AlignVCenter
+            renderType: Text.NativeRendering
+            color: UM.Theme.getColor("setting_unit")
+            font: UM.Theme.getFont("default")
         }
         }
     }
     }
 }
 }

+ 16 - 3
resources/qml/MachineSettings/SimpleCheckBox.qml

@@ -30,8 +30,9 @@ UM.TooltipArea
     property alias settingKey: propertyProvider.key
     property alias settingKey: propertyProvider.key
     property alias settingStoreIndex: propertyProvider.storeIndex
     property alias settingStoreIndex: propertyProvider.storeIndex
 
 
-    property alias labelText: checkBox.text
-    property alias labelFont: checkBox.font
+    property alias labelText: fieldLabel.text
+    property alias labelFont: fieldLabel.font
+    property alias labelWidth: fieldLabel.width
 
 
     property string tooltip: propertyProvider.properties.description
     property string tooltip: propertyProvider.properties.description
 
 
@@ -47,12 +48,24 @@ UM.TooltipArea
         watchedProperties: [ "value", "description" ]
         watchedProperties: [ "value", "description" ]
     }
     }
 
 
+    Label
+    {
+        id: fieldLabel
+        anchors.left: parent.left
+        anchors.verticalCenter: checkBox.verticalCenter
+        visible: text != ""
+        font: UM.Theme.getFont("medium")
+        renderType: Text.NativeRendering
+    }
+
     CuraCheckBox
     CuraCheckBox
     {
     {
         id: checkBox
         id: checkBox
+        anchors.left: fieldLabel.right
+        anchors.leftMargin: UM.Theme.getSize("default_margin").width
         checked: String(propertyProvider.properties.value).toLowerCase() != 'false'
         checked: String(propertyProvider.properties.value).toLowerCase() != 'false'
         height: simpleCheckBox.controlHeight
         height: simpleCheckBox.controlHeight
-        font: UM.Theme.getFont("medium")
+        text: ""
         onClicked:
         onClicked:
         {
         {
             propertyProvider.setPropertyValue("value", checked)
             propertyProvider.setPropertyValue("value", checked)

+ 282 - 168
resources/qml/WelcomePages/TestContent.qml

@@ -14,7 +14,7 @@ import "../MachineSettings"
 // This component contains the content for the "Welcome" page of the welcome on-boarding process.
 // This component contains the content for the "Welcome" page of the welcome on-boarding process.
 //
 //
 
 
-Row
+Item
 {
 {
     id: base
     id: base
     UM.I18nCatalog { id: catalog; name: "cura" }
     UM.I18nCatalog { id: catalog; name: "cura" }
@@ -22,193 +22,307 @@ Row
     anchors.left: parent.left
     anchors.left: parent.left
     anchors.right: parent.right
     anchors.right: parent.right
     anchors.top: parent.top
     anchors.top: parent.top
-    anchors.margins: UM.Theme.getSize("default_margin").width
 
 
-    property int labelWidth: 110
+    property int labelWidth: 130
+    property int controlWidth: UM.Theme.getSize("setting_control").width * 3 / 4
     property var labelFont: UM.Theme.getFont("medium")
     property var labelFont: UM.Theme.getFont("medium")
 
 
-    spacing: 10
+    property int columnWidth: (parent.width - 2 * UM.Theme.getSize("default_margin").width) / 2
+    property int columnSpacing: 10
+    property int propertyStoreIndex: 5  // definition_changes
 
 
-    // =======================================
-    // Left-side column for "Printer Settings"
-    // =======================================
-    Column
+    Item
     {
     {
-        spacing: 10
-
-        Label   // Title Label
-        {
-            text: catalog.i18nc("@title:label", "Printer Settings")
-            font: UM.Theme.getFont("medium_bold")
-        }
-
-        NumericTextFieldWithUnit  // "X (Width)"
-        {
-            id: machineXWidthField
-            containerStackId: Cura.MachineManager.activeMachineId
-            settingKey: "machine_width"
-            settingStoreIndex: 1 // TODO
-            labelText: catalog.i18nc("@label", "X (Width)")
-            labelFont: base.labelFont
-            labelWidth: base.labelWidth
-            unitText: catalog.i18nc("@label", "mm")
-            // TODO: add forceUpdateOnChangeFunction:
-        }
-
-        NumericTextFieldWithUnit  // "Y (Depth)"
-        {
-            id: machineYDepthField
-            containerStackId: Cura.MachineManager.activeMachineId
-            settingKey: "machine_depth"
-            settingStoreIndex: 1 // TODO
-            labelText: catalog.i18nc("@label", "Y (Depth)")
-            labelFont: base.labelFont
-            labelWidth: base.labelWidth
-            unitText: catalog.i18nc("@label", "mm")
-            // TODO: add forceUpdateOnChangeFunction:
-        }
-
-        NumericTextFieldWithUnit  // "Z (Height)"
-        {
-            id: machineZHeightField
-            containerStackId: Cura.MachineManager.activeMachineId
-            settingKey: "machine_height"
-            settingStoreIndex: 1 // TODO
-            labelText: catalog.i18nc("@label", "Z (Height)")
-            labelFont: base.labelFont
-            labelWidth: base.labelWidth
-            unitText: catalog.i18nc("@label", "mm")
-            // TODO: add forceUpdateOnChangeFunction:
-        }
-
-        ComboBoxWithOptions  // "Build plate shape"
+        id: upperBlock
+        anchors.top: parent.top
+        anchors.left: parent.left
+        anchors.right: parent.right
+        anchors.margins: UM.Theme.getSize("default_margin").width
+
+        height: childrenRect.height
+
+        // =======================================
+        // Left-side column for "Printer Settings"
+        // =======================================
+        Column
         {
         {
-            id: buildPlateShapeComboBox
-            containerStackId: Cura.MachineManager.activeMachineId
-            settingKey: "machine_shape"
-            settingStoreIndex: 1 // TODO
-            labelText: catalog.i18nc("@label", "Build plate shape")
-            labelWidth: base.labelWidth
-            // TODO: add forceUpdateOnChangeFunction:
+            anchors.top: parent.top
+            anchors.left: parent.left
+            width: base.columnWidth
+
+            spacing: base.columnSpacing
+
+            Label   // Title Label
+            {
+                text: catalog.i18nc("@title:label", "Printer Settings")
+                font: UM.Theme.getFont("medium_bold")
+                renderType: Text.NativeRendering
+            }
+
+            NumericTextFieldWithUnit  // "X (Width)"
+            {
+                id: machineXWidthField
+                containerStackId: Cura.MachineManager.activeMachineId
+                settingKey: "machine_width"
+                settingStoreIndex: propertyStoreIndex
+                labelText: catalog.i18nc("@label", "X (Width)")
+                labelFont: base.labelFont
+                labelWidth: base.labelWidth
+                controlWidth: base.controlWidth
+                unitText: catalog.i18nc("@label", "mm")
+                // TODO: add forceUpdateOnChangeFunction:
+            }
+
+            NumericTextFieldWithUnit  // "Y (Depth)"
+            {
+                id: machineYDepthField
+                containerStackId: Cura.MachineManager.activeMachineId
+                settingKey: "machine_depth"
+                settingStoreIndex: propertyStoreIndex
+                labelText: catalog.i18nc("@label", "Y (Depth)")
+                labelFont: base.labelFont
+                labelWidth: base.labelWidth
+                controlWidth: base.controlWidth
+                unitText: catalog.i18nc("@label", "mm")
+                // TODO: add forceUpdateOnChangeFunction:
+            }
+
+            NumericTextFieldWithUnit  // "Z (Height)"
+            {
+                id: machineZHeightField
+                containerStackId: Cura.MachineManager.activeMachineId
+                settingKey: "machine_height"
+                settingStoreIndex: propertyStoreIndex
+                labelText: catalog.i18nc("@label", "Z (Height)")
+                labelFont: base.labelFont
+                labelWidth: base.labelWidth
+                controlWidth: base.controlWidth
+                unitText: catalog.i18nc("@label", "mm")
+                // TODO: add forceUpdateOnChangeFunction:
+            }
+
+            ComboBoxWithOptions  // "Build plate shape"
+            {
+                id: buildPlateShapeComboBox
+                containerStackId: Cura.MachineManager.activeMachineId
+                settingKey: "machine_shape"
+                settingStoreIndex: propertyStoreIndex
+                labelText: catalog.i18nc("@label", "Build plate shape")
+                labelFont: base.labelFont
+                labelWidth: base.labelWidth
+                controlWidth: base.controlWidth
+                // TODO: add forceUpdateOnChangeFunction:
+            }
+
+            SimpleCheckBox  // "Origin at center"
+            {
+                id: originAtCenterCheckBox
+                containerStackId: Cura.MachineManager.activeMachineId
+                settingKey: "machine_center_is_zero"
+                settingStoreIndex: propertyStoreIndex
+                labelText: catalog.i18nc("@label", "Origin at center")
+                labelFont: base.labelFont
+                labelWidth: base.labelWidth
+                // TODO: add forceUpdateOnChangeFunction:
+            }
+
+            SimpleCheckBox  // "Heated bed"
+            {
+                id: heatedBedCheckBox
+                containerStackId: Cura.MachineManager.activeMachineId
+                settingKey: "machine_heated_bed"
+                settingStoreIndex: propertyStoreIndex
+                labelText: catalog.i18nc("@label", "Heated bed")
+                labelFont: base.labelFont
+                labelWidth: base.labelWidth
+                // TODO: add forceUpdateOnChangeFunction:
+            }
+
+            ComboBoxWithOptions  // "G-code flavor"
+            {
+                id: gcodeFlavorComboBox
+                containerStackId: Cura.MachineManager.activeMachineId
+                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
+            }
         }
         }
 
 
-        SimpleCheckBox  // "Origin at center"
+        // =======================================
+        // Right-side column for "Printhead Settings"
+        // =======================================
+        Column
         {
         {
-            id: originAtCenterCheckBox
-            containerStackId: Cura.MachineManager.activeMachineId
-            settingKey: "machine_center_is_zero"
-            settingStoreIndex: 1 // TODO
-            labelText: catalog.i18nc("@label", "Origin at center")
-            labelFont: base.labelFont
-            // TODO: add forceUpdateOnChangeFunction:
-        }
-
-        SimpleCheckBox  // "Heated bed"
-        {
-            id: heatedBedCheckBox
-            containerStackId: Cura.MachineManager.activeMachineId
-            settingKey: "machine_heated_bed"
-            settingStoreIndex: 1 // TODO
-            labelText: catalog.i18nc("@label", "Heated bed")
-            labelFont: base.labelFont
-            // TODO: add forceUpdateOnChangeFunction:
-        }
-
-        ComboBoxWithOptions  // "G-code flavor"
-        {
-            id: gcodeFlavorComboBox
-            containerStackId: Cura.MachineManager.activeMachineId
-            settingKey: "machine_gcode_flavor"
-            settingStoreIndex: 1 // TODO
-            labelText: catalog.i18nc("@label", "G-code flavor")
-            labelFont: base.labelFont
-            labelWidth: base.labelWidth
-            // TODO: add forceUpdateOnChangeFunction:
-            // TODO: add afterOnActivate: manager.updateHasMaterialsMetadata
+            anchors.top: parent.top
+            anchors.right: parent.right
+            width: base.columnWidth
+
+            spacing: base.columnSpacing
+
+            Label   // Title Label
+            {
+                text: catalog.i18nc("@title:label", "Printhead Settings")
+                font: UM.Theme.getFont("medium_bold")
+                renderType: Text.NativeRendering
+            }
+
+            PrintHeadMinMaxTextField  // "X min"
+            {
+                id: machineXMinField
+
+                settingStoreIndex: propertyStoreIndex
+
+                labelText: catalog.i18nc("@label", "X min")
+                labelFont: base.labelFont
+                labelWidth: base.labelWidth
+                controlWidth: base.controlWidth
+                unitText: catalog.i18nc("@label", "mm")
+
+                axisName: "x"
+                axisMinOrMax: "min"
+
+                // TODO: add forceUpdateOnChangeFunction:
+            }
+
+            PrintHeadMinMaxTextField  // "Y min"
+            {
+                id: machineYMinField
+
+                settingStoreIndex: propertyStoreIndex
+
+                labelText: catalog.i18nc("@label", "Y min")
+                labelFont: base.labelFont
+                labelWidth: base.labelWidth
+                controlWidth: base.controlWidth
+                unitText: catalog.i18nc("@label", "mm")
+
+                axisName: "y"
+                axisMinOrMax: "min"
+
+                // TODO: add forceUpdateOnChangeFunction:
+            }
+
+            PrintHeadMinMaxTextField  // "X max"
+            {
+                id: machineXMaxField
+
+                settingStoreIndex: propertyStoreIndex
+
+                labelText: catalog.i18nc("@label", "X max")
+                labelFont: base.labelFont
+                labelWidth: base.labelWidth
+                controlWidth: base.controlWidth
+                unitText: catalog.i18nc("@label", "mm")
+
+                axisName: "x"
+                axisMinOrMax: "max"
+
+                // TODO: add forceUpdateOnChangeFunction:
+            }
+
+            PrintHeadMinMaxTextField  // "Y max"
+            {
+                id: machineYMaxField
+
+                containerStackId: Cura.MachineManager.activeMachineId
+                settingKey: "machine_head_with_fans_polygon"
+                settingStoreIndex: propertyStoreIndex
+
+                labelText: catalog.i18nc("@label", "Y max")
+                labelFont: base.labelFont
+                labelWidth: base.labelWidth
+                controlWidth: base.controlWidth
+                unitText: catalog.i18nc("@label", "mm")
+
+                axisName: "y"
+                axisMinOrMax: "max"
+
+                // TODO: add forceUpdateOnChangeFunction:
+            }
+
+            NumericTextFieldWithUnit  // "Gantry Height"
+            {
+                id: machineGantryHeightField
+                containerStackId: Cura.MachineManager.activeMachineId
+                settingKey: "gantry_height"
+                settingStoreIndex: propertyStoreIndex
+                labelText: catalog.i18nc("@label", "Gantry Height")
+                labelFont: base.labelFont
+                labelWidth: base.labelWidth
+                controlWidth: base.controlWidth
+                unitText: catalog.i18nc("@label", "mm")
+                // TODO: add forceUpdateOnChangeFunction:
+            }
+
+            ComboBoxWithOptions  // "Number of Extruders"
+            {
+                id: numberOfExtrudersComboBox
+                containerStackId: Cura.MachineManager.activeMachineId
+                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
+
+                optionModel: ListModel
+                {
+                    id: extruderCountModel
+                    Component.onCompleted:
+                    {
+                        extruderCountModel.clear()
+                        for (var i = 1; i <= Cura.MachineManager.activeMachine.maxExtruderCount; i++)
+                        {
+                            extruderCountModel.append({text: String(i), value: i})
+                        }
+                    }
+                }
+            }
         }
         }
     }
     }
 
 
-    // =======================================
-    // Right-side column for "Printhead Settings"
-    // =======================================
-    Column
+    Item  // Start and End G-code
     {
     {
-        spacing: 10
-
-        Label   // Title Label
-        {
-            text: catalog.i18nc("@title:label", "Printhead Settings")
-            font: UM.Theme.getFont("medium_bold")
-        }
-
-        PrintHeadMinMaxTextField  // "X min"
+        id: lowerBlock
+        anchors.top: upperBlock.bottom
+        anchors.bottom: parent.bottom
+        anchors.left: parent.left
+        anchors.right: parent.right
+        anchors.margins: UM.Theme.getSize("default_margin").width
+
+        GcodeTextArea   // "Start G-code"
         {
         {
-            id: machineXMinField
-
-            settingStoreIndex: 1 // TODO
-
-            labelText: catalog.i18nc("@label", "X min")
-            labelFont: base.labelFont
-            labelWidth: base.labelWidth
-            unitText: catalog.i18nc("@label", "mm")
-
-            axisName: "x"
-            axisMinOrMax: "min"
-
-            // TODO: add forceUpdateOnChangeFunction:
-        }
-
-        PrintHeadMinMaxTextField  // "Y min"
-        {
-            id: machineYMinField
-
-            settingStoreIndex: 1 // TODO
-
-            labelText: catalog.i18nc("@label", "Y min")
-            labelFont: base.labelFont
-            labelWidth: base.labelWidth
-            unitText: catalog.i18nc("@label", "mm")
+            anchors.top: parent.top
+            anchors.bottom: parent.bottom
+            anchors.bottomMargin: UM.Theme.getSize("default_margin").height
+            anchors.left: parent.left
+            width: base.columnWidth - UM.Theme.getSize("default_margin").width
 
 
-            axisName: "y"
-            axisMinOrMax: "min"
-
-            // TODO: add forceUpdateOnChangeFunction:
-        }
-
-        PrintHeadMinMaxTextField  // "X max"
-        {
-            id: machineXMaxField
-
-            settingStoreIndex: 1 // TODO
-
-            labelText: catalog.i18nc("@label", "X max")
-            labelFont: base.labelFont
-            labelWidth: base.labelWidth
-            unitText: catalog.i18nc("@label", "mm")
-
-            axisName: "x"
-            axisMinOrMax: "max"
-
-            // TODO: add forceUpdateOnChangeFunction:
+            labelText: catalog.i18nc("@title:label", "Start G-code")
+            containerStackId: Cura.MachineManager.activeMachineId
+            settingKey: "machine_start_gcode"
+            settingStoreIndex: propertyStoreIndex
         }
         }
 
 
-        PrintHeadMinMaxTextField  // "Y max"
+        GcodeTextArea   // "End G-code"
         {
         {
-            id: machineYMaxField
+            anchors.top: parent.top
+            anchors.bottom: parent.bottom
+            anchors.bottomMargin: UM.Theme.getSize("default_margin").height
+            anchors.right: parent.right
+            width: base.columnWidth - UM.Theme.getSize("default_margin").width
 
 
+            labelText: catalog.i18nc("@title:label", "End G-code")
             containerStackId: Cura.MachineManager.activeMachineId
             containerStackId: Cura.MachineManager.activeMachineId
-            settingKey: "machine_head_with_fans_polygon"
-            settingStoreIndex: 1 // TODO
-
-            labelText: catalog.i18nc("@label", "Y max")
-            labelFont: base.labelFont
-            labelWidth: base.labelWidth
-            unitText: catalog.i18nc("@label", "mm")
-
-            axisName: "y"
-            axisMinOrMax: "max"
-
-            // TODO: add forceUpdateOnChangeFunction:
+            settingKey: "machine_end_gcode"
+            settingStoreIndex: propertyStoreIndex
         }
         }
     }
     }
 }
 }