// Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import UM 1.2 as UM import Cura 1.0 as Cura // // Quality profile // Item { id: qualityRow height: childrenRect.height Timer { id: qualitySliderChangeTimer interval: 50 running: false repeat: false onTriggered: { var item = Cura.QualityProfilesDropDownMenuModel.getItem(qualitySlider.value); Cura.MachineManager.activeQualityGroup = item.quality_group; } } Component.onCompleted: qualityModel.update() Connections { target: Cura.QualityProfilesDropDownMenuModel onItemsChanged: qualityModel.update() } Connections { target: base onVisibleChanged: { // update needs to be called when the widgets are visible, otherwise the step width calculation // will fail because the width of an invisible item is 0. if (visible) { qualityModel.update(); } } } ListModel { id: qualityModel property var totalTicks: 0 property var availableTotalTicks: 0 property var existingQualityProfile: 0 property var qualitySliderActiveIndex: 0 property var qualitySliderStepWidth: 0 property var qualitySliderAvailableMin: 0 property var qualitySliderAvailableMax: 0 property var qualitySliderMarginRight: 0 function update () { reset() var availableMin = -1 var availableMax = -1 for (var i = 0; i < Cura.QualityProfilesDropDownMenuModel.rowCount(); i++) { var qualityItem = Cura.QualityProfilesDropDownMenuModel.getItem(i) // Add each quality item to the UI quality model qualityModel.append(qualityItem) // Set selected value if (Cura.MachineManager.activeQualityType == qualityItem.quality_type) { // set to -1 when switching to user created profile so all ticks are clickable if (Cura.SimpleModeSettingsManager.isProfileUserCreated) { qualityModel.qualitySliderActiveIndex = -1 } else { qualityModel.qualitySliderActiveIndex = i } qualityModel.existingQualityProfile = 1 } // Set min available if (qualityItem.available && availableMin == -1) { availableMin = i } // Set max available if (qualityItem.available) { availableMax = i } } // Set total available ticks for active slider part if (availableMin != -1) { qualityModel.availableTotalTicks = availableMax - availableMin + 1 } // Calculate slider values calculateSliderStepWidth(qualityModel.totalTicks) calculateSliderMargins(availableMin, availableMax, qualityModel.totalTicks) qualityModel.qualitySliderAvailableMin = availableMin qualityModel.qualitySliderAvailableMax = availableMax } function calculateSliderStepWidth (totalTicks) { // Do not use Math.round otherwise the tickmarks won't be aligned qualityModel.qualitySliderStepWidth = totalTicks != 0 ? ((settingsColumnWidth - UM.Theme.getSize("print_setup_slider_handle").width) / (totalTicks)) : 0 } function calculateSliderMargins (availableMin, availableMax, totalTicks) { if (availableMin == -1 || (availableMin == 0 && availableMax == 0)) { // Do not use Math.round otherwise the tickmarks won't be aligned qualityModel.qualitySliderMarginRight = settingsColumnWidth } else if (availableMin == availableMax) { // Do not use Math.round otherwise the tickmarks won't be aligned qualityModel.qualitySliderMarginRight = (totalTicks - availableMin) * qualitySliderStepWidth } else { // Do not use Math.round otherwise the tickmarks won't be aligned qualityModel.qualitySliderMarginRight = (totalTicks - availableMax) * qualitySliderStepWidth } } function reset () { qualityModel.clear() qualityModel.availableTotalTicks = 0 qualityModel.existingQualityProfile = 0 // check, the ticks count cannot be less than zero qualityModel.totalTicks = Math.max(0, Cura.QualityProfilesDropDownMenuModel.rowCount() - 1) } } Cura.IconWithText { id: qualityRowTitle source: UM.Theme.getIcon("category_layer_height") text: catalog.i18nc("@label", "Layer Height") width: labelColumnWidth } // // // Show titles for the each quality slider ticks // Item // { // anchors.left: speedSlider.left // anchors.top: speedSlider.bottom // // Repeater // { // model: qualityModel // // Label // { // anchors.verticalCenter: parent.verticalCenter // anchors.top: parent.top // color: (Cura.MachineManager.activeMachine != null && Cura.QualityProfilesDropDownMenuModel.getItem(index).available) ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") // text: // { // var result = "" // if(Cura.MachineManager.activeMachine != null) // { // result = Cura.QualityProfilesDropDownMenuModel.getItem(index).layer_height // // if(result == undefined) // { // result = ""; // } // else // { // result = Number(Math.round(result + "e+2") + "e-2"); //Round to 2 decimals. Javascript makes this difficult... // if (result == undefined || result != result) //Parse failure. // { // result = ""; // } // } // } // return result // } // // x: // { // // Make sure the text aligns correctly with each tick // if (qualityModel.totalTicks == 0) // { // // If there is only one tick, align it centrally // return Math.round(((settingsColumnWidth) - width) / 2) // } // else if (index == 0) // { // return Math.round(settingsColumnWidth / qualityModel.totalTicks) * index // } // else if (index == qualityModel.totalTicks) // { // return Math.round(settingsColumnWidth / qualityModel.totalTicks) * index - width // } // else // { // return Math.round((settingsColumnWidth / qualityModel.totalTicks) * index - (width / 2)) // } // } // } // } // } // //Print speed slider Item { id: speedSlider height: childrenRect.height anchors { left: qualityRowTitle.right right: parent.right } // Draw unavailable slider Slider { id: unavailableSlider height: qualitySlider.height // Same height as the slider that is on top updateValueWhileDragging : false tickmarksEnabled: true minimumValue: 0 // maximumValue must be greater than minimumValue to be able to see the handle. While the value is strictly // speaking not always correct, it seems to have the correct behavior (switching from 0 available to 1 available) maximumValue: qualityModel.totalTicks stepSize: 1 width: parent.width style: SliderStyle { //Draw Unvailable line groove: Item { Rectangle { height: UM.Theme.getSize("print_setup_slider_groove").height width: control.width - UM.Theme.getSize("print_setup_slider_handle").width anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter color: UM.Theme.getColor("quality_slider_unavailable") } } handle: Item {} tickmarks: Repeater { id: qualityRepeater model: qualityModel.totalTicks > 0 ? qualityModel : 0 Rectangle { color: Cura.QualityProfilesDropDownMenuModel.getItem(index).available ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") implicitWidth: UM.Theme.getSize("print_setup_slider_tickmarks").width implicitHeight: UM.Theme.getSize("print_setup_slider_tickmarks").height anchors.verticalCenter: parent.verticalCenter // Do not use Math.round otherwise the tickmarks won't be aligned x: ((UM.Theme.getSize("print_setup_slider_handle").width / 2) - (UM.Theme.getSize("print_setup_slider_tickmarks").width / 2) + (qualityModel.qualitySliderStepWidth * index)) radius: Math.round(implicitWidth / 2) } } } // Create a mouse area on top of the unavailable profiles to show a specific tooltip MouseArea { anchors.fill: parent hoverEnabled: true enabled: !Cura.SimpleModeSettingsManager.isProfileUserCreated onEntered: { var tooltipContent: catalog.i18nc("@tooltip", "This quality profile is not available for you current material and nozzle configuration. Please change these to enable this quality profile") base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("thick_margin").width, customisedSettings.height), unavailableSlider.tooltipContent) } onExited: base.hideTooltip() } } // Draw available slider Slider { id: qualitySlider height: UM.Theme.getSize("print_setup_slider_handle").height // The handle is the widest element of the slider enabled: qualityModel.totalTicks > 0 && !Cura.SimpleModeSettingsManager.isProfileCustomized visible: qualityModel.availableTotalTicks > 0 updateValueWhileDragging : false minimumValue: qualityModel.qualitySliderAvailableMin >= 0 ? qualityModel.qualitySliderAvailableMin : 0 // maximumValue must be greater than minimumValue to be able to see the handle. While the value is strictly // speaking not always correct, it seems to have the correct behavior (switching from 0 available to 1 available) maximumValue: qualityModel.qualitySliderAvailableMax >= 1 ? qualityModel.qualitySliderAvailableMax : 1 stepSize: 1 value: qualityModel.qualitySliderActiveIndex width: qualityModel.qualitySliderStepWidth * (qualityModel.availableTotalTicks - 1) + UM.Theme.getSize("print_setup_slider_handle").width anchors.right: parent.right anchors.rightMargin: qualityModel.qualitySliderMarginRight style: SliderStyle { // Draw Available line groove: Item { Rectangle { height: UM.Theme.getSize("print_setup_slider_groove").height width: control.width - UM.Theme.getSize("print_setup_slider_handle").width anchors.verticalCenter: parent.verticalCenter // Do not use Math.round otherwise the tickmarks won't be aligned x: UM.Theme.getSize("print_setup_slider_handle").width / 2 color: UM.Theme.getColor("quality_slider_available") } } handle: Rectangle { id: qualityhandleButton color: UM.Theme.getColor("primary") implicitWidth: UM.Theme.getSize("print_setup_slider_handle").width implicitHeight: implicitWidth radius: Math.round(implicitWidth / 2) visible: !Cura.SimpleModeSettingsManager.isProfileCustomized && !Cura.SimpleModeSettingsManager.isProfileUserCreated && qualityModel.existingQualityProfile } } onValueChanged: { // only change if an active machine is set and the slider is visible at all. if (Cura.MachineManager.activeMachine != null && visible) { // prevent updating during view initializing. Trigger only if the value changed by user if (qualitySlider.value != qualityModel.qualitySliderActiveIndex && qualityModel.qualitySliderActiveIndex != -1) { // start updating with short delay qualitySliderChangeTimer.start() } } } // This mouse area is only used to capture the onHover state and don't propagate it to the unavailable mouse area MouseArea { anchors.fill: parent hoverEnabled: true enabled: !Cura.SimpleModeSettingsManager.isProfileUserCreated } } // This mouse area will only take the mouse events and show a tooltip when the profile in use is // a user created profile MouseArea { anchors.fill: parent hoverEnabled: true visible: Cura.SimpleModeSettingsManager.isProfileUserCreated onEntered: { var content = catalog.i18nc("@tooltip", "A custom profile is currently active. To enable the quality slider, choose a default quality profile in Custom tab") base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("thick_margin").width, customisedSettings.height), content) } onExited: base.hideTooltip() } } UM.SimpleButton { id: customisedSettings visible: Cura.SimpleModeSettingsManager.isProfileCustomized || Cura.SimpleModeSettingsManager.isProfileUserCreated height: Math.round(speedSlider.height * 0.8) width: Math.round(speedSlider.height * 0.8) anchors.verticalCenter: speedSlider.verticalCenter anchors.right: speedSlider.left anchors.rightMargin: Math.round(UM.Theme.getSize("thick_margin").width / 2) color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button"); iconSource: UM.Theme.getIcon("reset"); onClicked: { // if the current profile is user-created, switch to a built-in quality Cura.MachineManager.resetToUseDefaultQuality() } onEntered: { var content = catalog.i18nc("@tooltip","You have modified some profile settings. If you want to change these go to custom mode.") base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("thick_margin").width, customisedSettings.height), content) } onExited: base.hideTooltip() } }