// Copyright (c) 2021 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 import QtQuick.Controls 2.0 import UM 1.1 as UM SettingItem { id: base property var focusItem: input property string textBeforeEdit property bool textHasChanged property bool focusGainedByClick: false onFocusReceived: { textHasChanged = false; textBeforeEdit = focusItem.text; if(!focusGainedByClick) { // select all text when tabbing through fields (but not when selecting a field with the mouse) focusItem.selectAll(); } } contents: Rectangle { id: control anchors.fill: parent radius: UM.Theme.getSize("setting_control_radius").width border.width: UM.Theme.getSize("default_lining").width border.color: { if(!enabled) { return UM.Theme.getColor("setting_control_disabled_border") } switch(propertyProvider.properties.validationState) { case "ValidatorState.Invalid": 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(hovered || input.activeFocus) { return UM.Theme.getColor("setting_control_border_highlight") } return UM.Theme.getColor("setting_control_border") } color: { if(!enabled) { return UM.Theme.getColor("setting_control_disabled") } switch(propertyProvider.properties.validationState) { case "ValidatorState.Invalid": 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") } } Rectangle { anchors.fill: parent anchors.margins: Math.round(UM.Theme.getSize("default_lining").width) color: UM.Theme.getColor("setting_control_highlight") opacity: !control.hovered ? 0 : propertyProvider.properties.validationState == "ValidatorState.Valid" ? 1.0 : 0.35 } Label { anchors { left: parent.left leftMargin: Math.round(UM.Theme.getSize("setting_unit_margin").width) right: parent.right rightMargin: Math.round(UM.Theme.getSize("setting_unit_margin").width) verticalCenter: parent.verticalCenter } text: definition.unit //However the setting value is aligned, align the unit opposite. That way it stays readable with right-to-left languages. horizontalAlignment: (input.effectiveHorizontalAlignment == Text.AlignLeft) ? Text.AlignRight : Text.AlignLeft textFormat: Text.PlainText renderType: Text.NativeRendering color: UM.Theme.getColor("setting_unit") font: UM.Theme.getFont("default") } TextInput { id: input anchors { left: parent.left leftMargin: Math.round(UM.Theme.getSize("setting_unit_margin").width) right: parent.right rightMargin: Math.round(UM.Theme.getSize("setting_unit_margin").width) verticalCenter: parent.verticalCenter } renderType: Text.NativeRendering Keys.onTabPressed: { base.setActiveFocusToNextSetting(true) } Keys.onBacktabPressed: { base.setActiveFocusToNextSetting(false) } Keys.onReleased: { if (text != textBeforeEdit) { textHasChanged = true; } if (textHasChanged) { propertyProvider.setPropertyValue("value", text) } } onActiveFocusChanged: { if(activeFocus) { base.focusReceived(); } base.focusGainedByClick = false; } color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text") font: UM.Theme.getFont("default") selectByMouse: true maximumLength: (definition.type == "str" || definition.type == "[int]") ? -1 : 10 // Since [int] & str don't have a max length, they need to be clipped (since clipping is expensive, this // should be done as little as possible) clip: definition.type == "str" || definition.type == "[int]" validator: RegExpValidator { regExp: (definition.type == "[int]") ? /^\[?(\s*-?[0-9]{0,9}\s*,)*(\s*-?[0-9]{0,9})\s*\]?$/ : (definition.type == "int") ? /^-?[0-9]{0,10}$/ : (definition.type == "float") ? /^-?[0-9]{0,9}[.,]?[0-9]{0,3}$/ : /^.*$/ } // definition.type property from parent loader used to disallow fractional number entry Binding { target: input property: "text" value: { // Stacklevels // 0: user -> unsaved change // 1: quality changes -> saved change // 2: quality // 3: material -> user changed material in materialspage // 4: variant // 5: machine_changes // 6: machine if ((base.resolve != "None" && base.resolve) && (stackLevel != 0) && (stackLevel != 1)) { // We have a resolve function. Indicates that the setting is not settable per extruder and that // we have to choose between the resolved value (default) and the global value // (if user has explicitly set this). return base.resolve } else { return propertyProvider.properties.value } } when: !input.activeFocus } MouseArea { id: mouseArea anchors.fill: parent cursorShape: Qt.IBeamCursor onPressed: { if (!input.activeFocus) { base.focusGainedByClick = true input.forceActiveFocus() } mouse.accepted = false } } } } }